# Запросы в объектном стиле без моделей с поддержкой кеша данных (CORMless).
Идея библиотеки заключается, чтобы освободить разработчика от написания моделей. Если вам нравятся запросы ORM от django или sqlalchemy, но при этом вам не хочется создавать модели, то данная библиотека может вам понравиться. Также в ней присутствует функция кеширования данных, что может ускорить выдачу результатов. На данный момент кеширование предусмотренно либо на уровне процесса, либо в редисе. Библиотека расчитана на работу в синхронном и асинхронном режиме.
1. [Установка](#установка)
2. [Работа с таблицами](#работа-с-таблицами)
3. [Запросы к таблицам](#запросы-к-таблицам)
4. [Работа с кешем](#работа-с-кешем)
5. [Работа с БД в асинхронном режиме](#работа-с-бд-в-асинхронном-режиме)
6. [Асинхронный режим с удаленным кешем](#асинхронный-режим-с-удаленным-кешем)
6. [Выполнение сырых SQL запросов](#выполнение-сырых-sql-запросов)
## Установка
```
pip install query-tables
```
## Работа с таблицами.
Работа библиотеки будет продемонстрирована на этих таблицах:
Таблица `address`.
| Поле | Тип | Описание |
| ------------ | ------------ | ------------ |
| id | INTEGER | Ключ |
| street | TEXT | Улица |
| building | INTEGER | Здание |
Таблица `company`.
| Поле | Тип | Описание |
| ------------ | ------------ | ------------ |
| id | INTEGER | Ключ |
| name | TEXT | Название |
| ref_address | INTEGER | Ссылка на адрес |
| registration | TEXT | Время в формате ИСО |
Таблица `employees`.
| Поле | Тип | Описание |
| ------------ | ------------ | ------------ |
| id | INTEGER | Ключ |
| ref_person | INTEGER | Ссылка на персону |
| ref_company | INTEGER | Ссылка на компанию |
| hired | INTEGER | Время в формате unix epoch |
| dismissed | INTEGER | Время в формате unix epoch |
Таблица `person`.
| Поле | Тип | Описание |
| ------------ | ------------ | ------------ |
| id | INTEGER | Ключ |
| login | TEXT | Логин |
| name | TEXT | Имя |
| ref_address| INTEGER | Ссылка на адрес |
| age | INTEGER | Возраст |
Библиотека поддерживает работу с двумя БД: `sqlite` и `postgres`.
Работа с `sqlite`.
```python
from query_tables import Tables
from query_tables.db import SQLiteQuery
sqlite = SQLiteQuery(tests_dir / 'test_tables.db')
table = Tables(sqlite) # кеш отключен по умолчанию
# или так
table = Tables(sqlite, non_expired=True) # включен вечный кеш
# или так
table = Tables(sqlite, cache_ttl=300) # включен временный кеш на 300 сек.
# или так
connect = RedisConnect() # параметры соединения с редисом
redis_cache = RedisCache(connect)
tables = Tables(sqlite, cache=redis_cache)# кеш redis
```
При создание экземпляра `Tables` будут получен доступ ко всем таблицам.
Работа с `postgres` в многопоточном режиме.
```python
from query_tables import Tables
from query_tables.db import DBConfigPg, PostgresQuery
from query_tables.cache import RedisCache, RedisConnect
postgres = PostgresQuery(
DBConfigPg('localhost', 'test', 'postgres', 'postgres')
)
table = Tables(postgres) # кеш отключен по умолчанию
# или так
table = Tables(postgres, non_expired=True) # включен вечный кеш
# или так
table = Tables(postgres, cache_ttl=300) # включен временный кеш на 300 сек.
# или так
connect = RedisConnect() # параметры соединения с редисом
redis_cache = RedisCache(connect)
tables = Tables(postgres, cache=redis_cache)# кеш redis
```
При создание экземпляра `Tables` будет получен доступ к таблицам из схемы `public`. При желание вы можете передать другую схему.
Если нужен доступ к ограниченному числу таблиц из БД `postgres`:
```python
table = Tables(postgres, tables=['operators', 'opright'], non_expired=True)
```
Когда создается экземпляр `Tables` с использованием кеша на основе `redis` или другого удаленного кеша, то в этот момент структуры таблиц сохраняются в кеш. При повторном создание экземпляра `Tables` все таблицы будут взяты из кеша. Это может понадобиться, если вы работаете с веб-сервером.
Параметры `Tables`:
- `db`: Объект для доступа к БД.
- `prefix_table`: Префикс таблиц которые нужно загрузить. По умолчанию - пустая строка.
- `tables`: Список подключаемых таблиц. По умолчанию - нет.
- `table_schema`: Схема данных. По умолчанию - `public`.
- `cache_ttl`: Время кеширования данных. По умолчанию 0 секунд - кеширование отключено.
- `non_expired`: Вечный кеш без времени истечения. По умолчанию - выключен.
- `cache_maxsize`: Размер элементов в кеше.
- `cache`: Пользовательская реализация кеша.
Параметры `RedisConnect`:
- `host`: Хост редиса. По умолчанию - `127.0.0.1`
- `user`: Пользователь. По умолчанию - нет.
- `password`: Пароль. По умолчанию - нет.
- `port`: Порт. По умолчанию - 6379.
- `db`: БД. По умолчанию - 0.
Параметры `DBConfigPg`:
- `host`: Хост БД. По умолчанию - `127.0.0.1`
- `database`: Название БД. По умолчанию - нет.
- `user`: Пользователь. По умолчанию - нет.
- `password`: Пароль. По умолчанию - нет.
- `port`: Порт. По умолчанию - 5432
- `minconn`: Минимальное количество подключений в пуле - 1
- `maxconn`: Максимальное количество подключений в пуле - 10
Когда у вас есть экземпляр `Tables`, доступ к таблицам можно получить так:
```python
table['person']
```
## Запросы к таблицам.
После того, как вы создали экземпляр `Tables`, вы можете получать доступ к данным из таблиц.
```python
res = table['person'].filter(id=2).get()
print(res)
"""
[{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30}]
"""
res = table['person'].filter(name__like='%%4').get()
print(res)
"""
[{'person.id': 4, 'person.login': 'ytr', 'person.name': 'Anton 4', 'person.ref_address': 2, 'person.age': 35}]
"""
res = table['person'].filter(age__in=[30]).get()
print(res)
"""
[{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30}]
"""
res = table['person'].filter(age__between=(30, 31)).order_by(id='asc').get()
print(res)
"""
[{'person.id': 1, 'person.login': 'ant', 'person.name': 'Anton 1', 'person.ref_address': 1, 'person.age': 31},
{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30}]
"""
res = table['person'].filter(age__gte=35).get()
print(res)
"""
[{'person.id': 4, 'person.login': 'ytr', 'person.name': 'Anton 4', 'person.ref_address': 2, 'person.age': 35}]
"""
res = table['company'].filter(registration__between=('2020-01-04', '2020-01-05')).get()
print(res)
"""
[{'company.id': 2, 'company.name': 'Hex', 'company.ref_address': 4, 'company.registration': '2020-01-05'}]
"""
res = table['person'].order_by(id='desc').limit(1).get()
print(res)
"""
[{'person.id': 4, 'person.login': 'ytr', 'person.name': 'Anton 4', 'person.ref_address': 2, 'person.age': 35}]
"""
from query_tables.query import Join, LeftJoin
res = table['person'].join(
Join(table['address'], 'id', 'ref_address')
).filter(age__between=(25, 31)).get()
print(res)
"""
[{'person.id': 1, 'person.login': 'ant', 'person.name': 'Anton 1', 'person.ref_address': 1, 'person.age': 31, 'address.id': 1, 'address.street': 'Пушкина', 'address.building': 10},
{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30, 'address.id': 2, 'address.street': 'Наумова', 'address.building': 33}]
"""
res = table['person'].filter(id=2).join(
Join(table['address'], 'id', 'ref_address')
).join(
LeftJoin(table['employees'], 'ref_person', 'id').select(['id', 'ref_person', 'ref_company', 'hired']).join(
Join(table['company'], 'id', 'ref_company').join(
Join(table['address'], 'id', 'ref_address', 'compony_addr')
).filter(registration__between=('2020-01-02', '2020-01-06'))
)
).select(['id', 'name', 'age']).order_by(age='desc').get()
print(res)
"""
[{'address.id': 2, 'address.street': 'Наумова', 'address.building': 33, 'employees.id': 2, 'employees.ref_person': 2, 'employees.ref_company': 2, 'employees.hired': 1612588507, 'company.id': 2, 'company.name': 'Hex', 'company.ref_address': 4, 'company.registration': '2020-01-05', 'compony_addr.id': 4, 'compony_addr.street': 'Приморская', 'compony_addr.building': 8, 'person.id': 2, 'person.name': 'Anton 2', 'person.age': 30}]
"""
```
Для изменения метода фильтрации в условие можно добавить к модификатору `filter` параметр.
Есть следующие виды параметров в методе `filter`:
| Параметр | Оператор sql | Пример значений |
| :-------- | :------- | :--------
| `ilike` | `ilike` | `name__ilike='Ant%%'`|
| `like` | `like` | `name__ilike='Ant%%'`|
| `in` | `in` | `id__in=[1,2,3,4]`|
| `gt` | `>` | `age__gt=3`|
| `gte` | `>=` | `age__gte=3`|
| `lt` | `<` | `age__lt=3`|
| `lte` | `<=` | `age__lte=3`|
| `between` | `between` | `age__between=(5,6)`|
| `isnull` | `is null` | `name__isnull=None`|
| `isnotnull` | `is not null` | `name__isnotnull=None`|
| `notequ` | `!=` | `age__notequ=5`|
Доступные методы для конструирования запроса SQL из таблицы `table['person']`, а также из`Join` и `LeftJoin`. Данные методы не взаимодействют с БД, они только помогают собрать запрос:
- `select`: Для выбора выводимых полей.
- `join`: Объединение таблиц.
- `filter`: Правила фильтрации.
- `order_by`: Сортировка для полей.
- `limit`: Ограничения по количеству.
Для связывания таблиц используется две обертки:
```python
from query_tables.query import Join, LeftJoin
```
- `Join`: Если вам нужно выводит записи, только если они есть в join таблице.
- `LeftJoin`: Если вам нужно вывести записи, даже если их нет в join таблице.
Параметры для `Join`, `LeftJoin`:
- `join_table`: Таблица которая соединяется с другой таблицей.
- `join_field`: Поле join таблицы.
- `ext_field`: Поле внешней таблицы, с которой идет соединение.
- `table_alias`: Псевдоним для таблицы (*когда
одна и та же таблицы соединяется больше одного раза*).
Если ваш экземпляр `Tables` будет кешировать данные, то здесь нужно учитывать, когда и в какой момент нужно очищать кеш.
Предположим есть три запроса к БД, которые были созданы, но еще не выполнены. Пока данных нет, кеш пуст.
```python
query1 = table['person'].join(
Join(table['address'], 'id', 'ref_address')
).filter(age__between=(30, 33), name__like='Anton%%').order_by(id='desc')
query2 = table['person'].filter(id=2).join(
Join(table['address'], 'id', 'ref_address')
).join(
LeftJoin(table['employees'], 'ref_person', 'id').join(
Join(table['company'], 'id', 'ref_company').join(
Join(table['address'], 'id', 'ref_address', 'compony_addr')
).filter(registration__between=('2020-01-02', '2020-01-06'))
)
).order_by(age='desc')
query3 = table['person'].filter(id=3).join(
LeftJoin(table['employees'], 'ref_person', 'id')
)
```
Выполним запросы. Получение данных из БД.
```python
res = query1.get()
res = query2.get()
res = query3.get()
```
Теперь в следующий раз, когда вы захотите получить данные, они будут браться из кеша.
```python
res = query1.get()
res = query2.get()
res = query3.get()
```
Но что если вы измените данные в таблице? Если это сделать вручную из БД, то данные у нас остануться не актуальными. Изменение данных в БД нужно проводить через методы изменения данных по выбранной таблице.
```python
# вставка записей в БД
table['address'].insert([dict(
street='123',
building=777
)])
# обновление записей в БД
table['address'].filter(id=1).update(building=11)
# удаление записей из БД
table['address'].filter(id=1).delete()
```
В этом случае кеш запросов `query1` и `query2` будут очищены, так как они используют таблицу, в которой произошли изменения.
Также заметьте, что для вставки записей в БД мы используем список словарей. Это значит, что можно вставлять больше одной записи в БД за раз.
Получаем снова данные из БД.
```python
res = query1.get()
res = query2.get()
```
Если вам не нужно изменять данные в БД, но вы желаете, чтобы запросы в кеше, которые используют таблицу `address` были очищены, то можно сделать так:
```python
table['address'].delete_cache_table()
```
Получаем снова данные из БД.
```python
res = query1.get()
res = query2.get()
```
## Работа с кешем.
> Не пытайтесь получить доступ к кешу, если он у вас выключен. Это приведет к ошибке.
Давайте снова выполним запрос.
```python
# сохраняем запрос
query = table['person'].join(
Join(table['address'], 'id', 'ref_address')
).filter(age__between=(30, 33), name__like='Anton%%').order_by(id='desc')
query.get() # получаем данные по запросу
res = query.cache.get() # потом можно взять из кеша
# либо
res = query.get() # если кеш включен
print(res)
"""
[{'person.id': 3, 'person.login': 'geg', 'person.name': 'Anton 3', 'person.ref_address': 3, 'person.age': 33, 'address.id': 3, 'address.street': 'Гринвич', 'address.building': 12},
{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30, 'address.id': 2, 'address.street': 'Наумова', 'address.building': 33},
{'person.id': 1, 'person.login': 'ant', 'person.name': 'Anton 1', 'person.ref_address': 1, 'person.age': 31, 'address.id': 1, 'address.street': 'Пушкина', 'address.building': 10}]
"""
```
Теперь ваши данные находятся в кеше. Но что если вам нужно получить или изменить эти данные с учетов фильтрации кеша?
```python
# Получить список данных по выборке.
# В фильтре доступно только строгое равенство полей.
res = query.cache.filter({'person.id': 1}).get()
# Обновление данных по условию.
query.cache.filter({'person.id': 1}).update({'person.name': 'Tony 1', 'person.age': 32})
# Вставить новую запись в кеш.
query.cache.insert({
'person.id': 6,
'person.login': 'qqq',
'person.name': 'Anton 6',
'person.ref_address': 0,
'person.age': 0,
'address.id': 6,
'address.street': 'ytutyu',
'address.building': 567
})
# Удалить запись из кеша.
query.cache.filter({'person.id': 6}).delete()
```
Изменение данных через кеш не влечет за собой изменение данных в БД. В данном случае вы сами должны получить из БД данные и изменить их в кеше, чтобы не сбрасывать кеш.
Мы знаем, что запись с ИД 9 была изменена. Давайте ее получим:
```python
query_9 = table['person'].join(
Join(table['address'], 'id', 'ref_address')
).filter(id=9)
res: list = query_9.get()
# Теперь обновим наш кеш из прошлого запроса.
query.cache.filter({'person.id': 9}).update(**res[0])
```
Запрос query_9 будет закеширован. Давай сброси кеш по конкретному запросу.
```python
query_9.delete_cache_query()
```
Для очищение всего кеша используйте:
```python
table.clear_cache()
```
## Работа с БД в асинхронном режиме.
Конструктор запросов остался без изменений. Но запросы к БД будут выглядить по другому, к ним нужно добавить `await`.
Создаем экземпляр `TablesAsync`.
```python
from query_tables import TablesAsync
from query_tables.cache import RedisConnect, AsyncRedisCache
from query_tables.db import (
AsyncSQLiteQuery,
DBConfigPg,
AsyncPostgresQuery
)
sqlite_async = AsyncSQLiteQuery(tests_dir / 'test_db.db')
postgres_async = AsyncPostgresQuery(
DBConfigPg('localhost', 'test', 'postgres', 'postgres')
)
table = TablesAsync(sqlite_async, non_expired=True)
await table.init()
# или так
table = TablesAsync(postgres_async, non_expired=True)
await table.init()
# или так
redis = AsyncRedisCache(RedisConnect())
table = TablesAsync(postgres_async, cache=redis)
await table.init()
```
Получаем данные и проводим изменения в БД.
```python
res1 = await table['person'].filter(id=2).get()
res2 = await table['person'].filter(id=4).join(
Join(table['employees'], 'ref_person', 'id')
).get()
query = table['person'].filter(id=4).join(
LeftJoin(table['employees'], 'ref_person', 'id')
)
res3 = await query.get()
await table['person'].insert([dict(
login='tt',
name='Ton',
ref_address=1,
age=55
)])
await table['person'].filter(id=9).update(login='ant2', age=32)
await table['person'].filter(id=9).delete()
```
## Асинхронный режим с удаленным кешем.
Принцип доступка к данным из локального кеша, который находится в памяти процесса, не изменился. Но получение доступка к удаленному кешу был изменен.
Создаем экземпляр `TablesAsync`.
```python
from query_tables import TablesAsync
from query_tables.cache import RedisConnect, AsyncRedisCache
from query_tables.db import (
DBConfigPg,
AsyncPostgresQuery
)
postgres_async = AsyncPostgresQuery(
DBConfigPg('localhost', 'test', 'postgres', 'postgres')
)
redis = AsyncRedisCache(RedisConnect())
table = TablesAsync(postgres_async, cache=redis)
await table.init()
```
Запросы на получения и изменения данных в кеше.
```python
# сохраняем запрос
query = table['person'].join(
Join(table['address'], 'id', 'ref_address')
).filter(age__between=(30, 33), name__like='Anton%%').order_by(id='desc')
await query.get() # получаем данные по запросу из БД
res = await query.cache.get() # потом можно взять из кеша
# либо
res = await query.get() # если кеш включен
print(res)
"""
[{'person.id': 3, 'person.login': 'geg', 'person.name': 'Anton 3', 'person.ref_address': 3, 'person.age': 33, 'address.id': 3, 'address.street': 'Гринвич', 'address.building': 12},
{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30, 'address.id': 2, 'address.street': 'Наумова', 'address.building': 33},
{'person.id': 1, 'person.login': 'ant', 'person.name': 'Anton 1', 'person.ref_address': 1, 'person.age': 31, 'address.id': 1, 'address.street': 'Пушкина', 'address.building': 10}]
"""
# обновляем запись в кеше по id
await query.cache.filter({'person.id': 1}).update({'person.name': 'Tony 1', 'person.age': 32})
# вставка новой записи в кеш
await query.cache.insert({
'person.id': 6,
'person.login': 'qqq',
'person.name': 'Anton 6',
'person.ref_address': 0,
'person.age': 0,
'address.id': 6,
'address.street': 'ytutyu',
'address.building': 567
})
# удаление этой записи из кеша
await query.cache.filter({'person.id': 6}).delete()
# удаление данных по запросу из кеша
await query.delete_cache_query()
# очищение кеша
await table.clear_cache()
```
## Выполнение сырых SQL запросов.
Это может понадобиться, потому как ваш запрос может быть большой или вы хотели бы получить данные не из кеша.
Для выполнение сырых sql запросов нужно выполнить метод `query` со строкой sql запроса.
```python
from query_tables import Tables
from query_tables.db import DBConfigPg, PostgresQuery
from query_tables.cache import RedisCache, RedisConnect
postgres = PostgresQuery(
DBConfigPg('localhost', 'test', 'postgres', 'postgres')
)
connect = RedisConnect() # параметры соединения с редисом
redis_cache = RedisCache(connect)
tables = Tables(postgres, cache=redis_cache)# кеш redis
# получение списка кортежей
rows = tables.query('select * from person')
```
Если все же вы хотели бы его закешировать.
```python
query = 'select * from person'
rows = tables.query(query, cache=True)
```
Это извлекает данные из БД и сразу их кеширует по sql запросу.
В следующий раз получаем данные из кеша:
```python
rows = tables.query(query, cache=True)
```
Предположим вы знаете, что в таблице были изменения, и вы хотели бы снова получить их из БД в кеш.
Для этого нужно установить флаг `delete_cache`. Это удалит старые данные из кеша.
```python
rows = tables.query(query, cache=True, delete_cache=True)
```
Если же нужно просто удалить данные из кеша по запросу.
```python
rows = tables.query(query, delete_cache=True)
```
В следующий раз получаем данные из БД:
```python
rows = tables.query(query, cache=True)
```
Для асинхронного режима добавляем `await`:
```python
from query_tables import TablesAsync
from query_tables.cache import RedisConnect, AsyncRedisCache
from query_tables.db import (
DBConfigPg,
AsyncPostgresQuery
)
postgres_async = AsyncPostgresQuery(
DBConfigPg('localhost', 'test', 'postgres', 'postgres')
)
redis = AsyncRedisCache(RedisConnect())
table = TablesAsync(postgres_async, cache=redis)
await table.init()
query = 'select * from person'
rows = await tables.query(query)
```
Raw data
{
"_id": null,
"home_page": null,
"name": "query-tables",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "cache orm sql table redis postgres sqlite asyncio python",
"author": "\u0410\u043d\u0442\u043e\u043d \u0413\u043b\u044b\u0437\u0438\u043d",
"author_email": "tosha.glyzin@mail.ru",
"download_url": null,
"platform": null,
"description": "\n# \u0417\u0430\u043f\u0440\u043e\u0441\u044b \u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435 \u0431\u0435\u0437 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043a\u0435\u0448\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 (CORMless).\n\n\u0418\u0434\u0435\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043e\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439. \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0440\u0430\u0432\u044f\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u044b ORM \u043e\u0442 django \u0438\u043b\u0438 sqlalchemy, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432\u0430\u043c \u043d\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438, \u0442\u043e \u0434\u0430\u043d\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u043c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f. \u0422\u0430\u043a\u0436\u0435 \u0432 \u043d\u0435\u0439 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0432\u044b\u0434\u0430\u0447\u0443 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u043e \u043b\u0438\u0431\u043e \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u043b\u0438\u0431\u043e \u0432 \u0440\u0435\u0434\u0438\u0441\u0435. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0440\u0430\u0441\u0447\u0438\u0442\u0430\u043d\u0430 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0432 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435.\n\n1. [\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430](#\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430)\n2. [\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438](#\u0440\u0430\u0431\u043e\u0442\u0430-\u0441-\u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438)\n3. [\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c](#\u0437\u0430\u043f\u0440\u043e\u0441\u044b-\u043a-\u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c)\n4. [\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u0435\u0448\u0435\u043c](#\u0440\u0430\u0431\u043e\u0442\u0430-\u0441-\u043a\u0435\u0448\u0435\u043c)\n5. [\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0411\u0414 \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435](#\u0440\u0430\u0431\u043e\u0442\u0430-\u0441-\u0431\u0434-\u0432-\u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c-\u0440\u0435\u0436\u0438\u043c\u0435)\n6. [\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c \u0441 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u043c \u043a\u0435\u0448\u0435\u043c](#\u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439-\u0440\u0435\u0436\u0438\u043c-\u0441-\u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u043c-\u043a\u0435\u0448\u0435\u043c)\n6. [\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u044b\u0440\u044b\u0445 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432](#\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435-\u0441\u044b\u0440\u044b\u0445-sql-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432)\n\n## \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\n\n```\npip install query-tables\n```\n\n## \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438.\n\n\u0420\u0430\u0431\u043e\u0442\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u044d\u0442\u0438\u0445 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445:\n\n\u0422\u0430\u0431\u043b\u0438\u0446\u0430 `address`.\n\n| \u041f\u043e\u043b\u0435 | \u0422\u0438\u043f | \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 |\n| ------------ | ------------ | ------------ |\n| id | INTEGER | \u041a\u043b\u044e\u0447 |\n| street | TEXT | \u0423\u043b\u0438\u0446\u0430 |\n| building | INTEGER | \u0417\u0434\u0430\u043d\u0438\u0435 |\n\n\n\u0422\u0430\u0431\u043b\u0438\u0446\u0430 `company`.\n\n| \u041f\u043e\u043b\u0435 | \u0422\u0438\u043f | \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 |\n| ------------ | ------------ | ------------ |\n| id | INTEGER | \u041a\u043b\u044e\u0447 |\n| name | TEXT | \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 |\n| ref_address | INTEGER | \u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 |\n| registration | TEXT | \u0412\u0440\u0435\u043c\u044f \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0418\u0421\u041e |\n\n\n\u0422\u0430\u0431\u043b\u0438\u0446\u0430 `employees`.\n\n| \u041f\u043e\u043b\u0435 | \u0422\u0438\u043f | \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 |\n| ------------ | ------------ | ------------ |\n| id | INTEGER | \u041a\u043b\u044e\u0447 |\n| ref_person | INTEGER | \u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0443 |\n| ref_company | INTEGER | \u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044e |\n| hired | INTEGER | \u0412\u0440\u0435\u043c\u044f \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 unix epoch |\n| dismissed | INTEGER | \u0412\u0440\u0435\u043c\u044f \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 unix epoch |\n\n\n\u0422\u0430\u0431\u043b\u0438\u0446\u0430 `person`.\n\n| \u041f\u043e\u043b\u0435 | \u0422\u0438\u043f | \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 |\n| ------------ | ------------ | ------------ |\n| id | INTEGER | \u041a\u043b\u044e\u0447 |\n| login | TEXT | \u041b\u043e\u0433\u0438\u043d |\n| name | TEXT | \u0418\u043c\u044f |\n| ref_address| INTEGER | \u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 |\n| age | INTEGER | \u0412\u043e\u0437\u0440\u0430\u0441\u0442 |\n\n\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0434\u0432\u0443\u043c\u044f \u0411\u0414: `sqlite` \u0438 `postgres`.\n\n\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 `sqlite`. \n```python\nfrom query_tables import Tables\nfrom query_tables.db import SQLiteQuery\n\nsqlite = SQLiteQuery(tests_dir / 'test_tables.db')\ntable = Tables(sqlite) # \u043a\u0435\u0448 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e\n# \u0438\u043b\u0438 \u0442\u0430\u043a\ntable = Tables(sqlite, non_expired=True) # \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u0432\u0435\u0447\u043d\u044b\u0439 \u043a\u0435\u0448\n# \u0438\u043b\u0438 \u0442\u0430\u043a\ntable = Tables(sqlite, cache_ttl=300) # \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u043a\u0435\u0448 \u043d\u0430 300 \u0441\u0435\u043a.\n# \u0438\u043b\u0438 \u0442\u0430\u043a\nconnect = RedisConnect() # \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 \u0440\u0435\u0434\u0438\u0441\u043e\u043c\nredis_cache = RedisCache(connect)\ntables = Tables(sqlite, cache=redis_cache)# \u043a\u0435\u0448 redis\n```\n\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 `Tables` \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u043e \u0432\u0441\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c.\n\n\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 `postgres` \u0432 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435. \n```python\nfrom query_tables import Tables\nfrom query_tables.db import DBConfigPg, PostgresQuery\nfrom query_tables.cache import RedisCache, RedisConnect\n\npostgres = PostgresQuery(\n DBConfigPg('localhost', 'test', 'postgres', 'postgres')\n)\ntable = Tables(postgres) # \u043a\u0435\u0448 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e\n# \u0438\u043b\u0438 \u0442\u0430\u043a\ntable = Tables(postgres, non_expired=True) # \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u0432\u0435\u0447\u043d\u044b\u0439 \u043a\u0435\u0448\n# \u0438\u043b\u0438 \u0442\u0430\u043a\ntable = Tables(postgres, cache_ttl=300) # \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u043a\u0435\u0448 \u043d\u0430 300 \u0441\u0435\u043a.\n# \u0438\u043b\u0438 \u0442\u0430\u043a\nconnect = RedisConnect() # \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 \u0440\u0435\u0434\u0438\u0441\u043e\u043c\nredis_cache = RedisCache(connect)\ntables = Tables(postgres, cache=redis_cache)# \u043a\u0435\u0448 redis\n\n```\n\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 `Tables` \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c \u0438\u0437 \u0441\u0445\u0435\u043c\u044b `public`. \u041f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0443\u044e \u0441\u0445\u0435\u043c\u0443.\n\n\u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u043e\u043c\u0443 \u0447\u0438\u0441\u043b\u0443 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438\u0437 \u0411\u0414 `postgres`:\n```python\ntable = Tables(postgres, tables=['operators', 'opright'], non_expired=True)\n```\n\n\u041a\u043e\u0433\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 `Tables` \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u0435\u0448\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 `redis` \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u0435\u0448\u0430, \u0442\u043e \u0432 \u044d\u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0442\u0430\u0431\u043b\u0438\u0446 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043a\u0435\u0448. \u041f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 `Tables` \u0432\u0441\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0431\u0443\u0434\u0443\u0442 \u0432\u0437\u044f\u0442\u044b \u0438\u0437 \u043a\u0435\u0448\u0430. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f, \u0435\u0441\u043b\u0438 \u0432\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u0441 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c. \n\n\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b `Tables`:\n- `db`: \u041e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0411\u0414.\n- `prefix_table`: \u041f\u0440\u0435\u0444\u0438\u043a\u0441 \u0442\u0430\u0431\u043b\u0438\u0446 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - \u043f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430.\n- `tables`: \u0421\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0445 \u0442\u0430\u0431\u043b\u0438\u0446. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - \u043d\u0435\u0442.\n- `table_schema`: \u0421\u0445\u0435\u043c\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - `public`.\n- `cache_ttl`: \u0412\u0440\u0435\u043c\u044f \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e 0 \u0441\u0435\u043a\u0443\u043d\u0434 - \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u043e.\n- `non_expired`: \u0412\u0435\u0447\u043d\u044b\u0439 \u043a\u0435\u0448 \u0431\u0435\u0437 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u044f. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d.\n- `cache_maxsize`: \u0420\u0430\u0437\u043c\u0435\u0440 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u043a\u0435\u0448\u0435.\n- `cache`: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u0435\u0448\u0430.\n\n\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b `RedisConnect`:\n- `host`: \u0425\u043e\u0441\u0442 \u0440\u0435\u0434\u0438\u0441\u0430. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - `127.0.0.1`\n- `user`: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - \u043d\u0435\u0442.\n- `password`: \u041f\u0430\u0440\u043e\u043b\u044c. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - \u043d\u0435\u0442.\n- `port`: \u041f\u043e\u0440\u0442. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - 6379.\n- `db`: \u0411\u0414. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - 0.\n\n\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b `DBConfigPg`:\n- `host`: \u0425\u043e\u0441\u0442 \u0411\u0414. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - `127.0.0.1`\n- `database`: \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0411\u0414. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - \u043d\u0435\u0442. \n- `user`: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - \u043d\u0435\u0442.\n- `password`: \u041f\u0430\u0440\u043e\u043b\u044c. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - \u043d\u0435\u0442.\n- `port`: \u041f\u043e\u0440\u0442. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - 5432\n- `minconn`: \u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0432 \u043f\u0443\u043b\u0435 - 1\n- `maxconn`: \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0432 \u043f\u0443\u043b\u0435 - 10\n\n\u041a\u043e\u0433\u0434\u0430 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 `Tables`, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0430\u043a:\n```python\ntable['person']\n```\n \n## \u0417\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c.\n\n\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0432\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 `Tables`, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0434\u0430\u043d\u043d\u044b\u043c \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446.\n\n```python\nres = table['person'].filter(id=2).get()\nprint(res)\n\"\"\"\n[{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30}]\n\"\"\"\n\nres = table['person'].filter(name__like='%%4').get()\nprint(res)\n\"\"\"\n[{'person.id': 4, 'person.login': 'ytr', 'person.name': 'Anton 4', 'person.ref_address': 2, 'person.age': 35}]\n\"\"\"\n\nres = table['person'].filter(age__in=[30]).get()\nprint(res)\n\"\"\"\n[{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30}]\n\"\"\"\n\nres = table['person'].filter(age__between=(30, 31)).order_by(id='asc').get()\nprint(res)\n\"\"\"\n[{'person.id': 1, 'person.login': 'ant', 'person.name': 'Anton 1', 'person.ref_address': 1, 'person.age': 31}, \n{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30}]\n\"\"\"\n\nres = table['person'].filter(age__gte=35).get()\nprint(res)\n\"\"\"\n[{'person.id': 4, 'person.login': 'ytr', 'person.name': 'Anton 4', 'person.ref_address': 2, 'person.age': 35}]\n\"\"\"\n\nres = table['company'].filter(registration__between=('2020-01-04', '2020-01-05')).get()\nprint(res)\n\"\"\"\n[{'company.id': 2, 'company.name': 'Hex', 'company.ref_address': 4, 'company.registration': '2020-01-05'}]\n\"\"\"\n\nres = table['person'].order_by(id='desc').limit(1).get()\nprint(res)\n\"\"\"\n[{'person.id': 4, 'person.login': 'ytr', 'person.name': 'Anton 4', 'person.ref_address': 2, 'person.age': 35}]\n\"\"\"\n\nfrom query_tables.query import Join, LeftJoin\n\nres = table['person'].join(\n Join(table['address'], 'id', 'ref_address')\n).filter(age__between=(25, 31)).get()\nprint(res)\n\"\"\"\n[{'person.id': 1, 'person.login': 'ant', 'person.name': 'Anton 1', 'person.ref_address': 1, 'person.age': 31, 'address.id': 1, 'address.street': '\u041f\u0443\u0448\u043a\u0438\u043d\u0430', 'address.building': 10}, \n{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30, 'address.id': 2, 'address.street': '\u041d\u0430\u0443\u043c\u043e\u0432\u0430', 'address.building': 33}]\n\"\"\"\n\nres = table['person'].filter(id=2).join(\n Join(table['address'], 'id', 'ref_address')\n).join(\n LeftJoin(table['employees'], 'ref_person', 'id').select(['id', 'ref_person', 'ref_company', 'hired']).join(\n Join(table['company'], 'id', 'ref_company').join(\n Join(table['address'], 'id', 'ref_address', 'compony_addr')\n ).filter(registration__between=('2020-01-02', '2020-01-06'))\n )\n).select(['id', 'name', 'age']).order_by(age='desc').get()\nprint(res)\n\"\"\"\n[{'address.id': 2, 'address.street': '\u041d\u0430\u0443\u043c\u043e\u0432\u0430', 'address.building': 33, 'employees.id': 2, 'employees.ref_person': 2, 'employees.ref_company': 2, 'employees.hired': 1612588507, 'company.id': 2, 'company.name': 'Hex', 'company.ref_address': 4, 'company.registration': '2020-01-05', 'compony_addr.id': 4, 'compony_addr.street': '\u041f\u0440\u0438\u043c\u043e\u0440\u0441\u043a\u0430\u044f', 'compony_addr.building': 8, 'person.id': 2, 'person.name': 'Anton 2', 'person.age': 30}]\n\"\"\"\n```\n\n\u0414\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443 `filter` \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440.\n\n\u0415\u0441\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0432\u0438\u0434\u044b \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 `filter`:\n\n| \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 | \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 sql | \u041f\u0440\u0438\u043c\u0435\u0440 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 |\n| :-------- | :------- | :--------\n| `ilike` | `ilike` | `name__ilike='Ant%%'`|\n| `like` | `like` | `name__ilike='Ant%%'`|\n| `in` | `in` | `id__in=[1,2,3,4]`|\n| `gt` | `>` | `age__gt=3`|\n| `gte` | `>=` | `age__gte=3`|\n| `lt` | `<` | `age__lt=3`|\n| `lte` | `<=` | `age__lte=3`|\n| `between` | `between` | `age__between=(5,6)`|\n| `isnull` | `is null` | `name__isnull=None`|\n| `isnotnull` | `is not null` | `name__isnotnull=None`|\n| `notequ` | `!=` | `age__notequ=5`|\n\n\n\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 SQL \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b `table['person']`, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u0437`Join` \u0438 `LeftJoin`. \u0414\u0430\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043d\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u044e\u0442 \u0441 \u0411\u0414, \u043e\u043d\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441:\n- `select`: \u0414\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u044b\u0432\u043e\u0434\u0438\u043c\u044b\u0445 \u043f\u043e\u043b\u0435\u0439.\n- `join`: \u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446.\n- `filter`: \u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438.\n- `order_by`: \u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0435\u0439.\n- `limit`: \u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443.\n\n\u0414\u043b\u044f \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u0432\u0435 \u043e\u0431\u0435\u0440\u0442\u043a\u0438:\n```python\nfrom query_tables.query import Join, LeftJoin\n```\n- `Join`: \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0437\u0430\u043f\u0438\u0441\u0438, \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0435\u0441\u0442\u044c \u0432 join \u0442\u0430\u0431\u043b\u0438\u0446\u0435.\n- `LeftJoin`: \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0437\u0430\u043f\u0438\u0441\u0438, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0438\u0445 \u043d\u0435\u0442 \u0432 join \u0442\u0430\u0431\u043b\u0438\u0446\u0435.\n\n\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f `Join`, `LeftJoin`:\n- `join_table`: \u0422\u0430\u0431\u043b\u0438\u0446\u0430 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442\u0441\u044f \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u0435\u0439.\n- `join_field`: \u041f\u043e\u043b\u0435 join \u0442\u0430\u0431\u043b\u0438\u0446\u044b.\n- `ext_field`: \u041f\u043e\u043b\u0435 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0438\u0434\u0435\u0442 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435.\n- `table_alias`: \u041f\u0441\u0435\u0432\u0434\u043e\u043d\u0438\u043c \u0434\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b (*\u043a\u043e\u0433\u0434\u0430 \n \u043e\u0434\u043d\u0430 \u0438 \u0442\u0430 \u0436\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0430*).\n\n\u0415\u0441\u043b\u0438 \u0432\u0430\u0448 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 `Tables` \u0431\u0443\u0434\u0435\u0442 \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043d\u0443\u0436\u043d\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0438 \u0432 \u043a\u0430\u043a\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0443\u0436\u043d\u043e \u043e\u0447\u0438\u0449\u0430\u0442\u044c \u043a\u0435\u0448.\n\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c \u0435\u0441\u0442\u044c \u0442\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a \u0411\u0414, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u044b, \u043d\u043e \u0435\u0449\u0435 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b. \u041f\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u0442, \u043a\u0435\u0448 \u043f\u0443\u0441\u0442.\n```python\nquery1 = table['person'].join(\n Join(table['address'], 'id', 'ref_address')\n).filter(age__between=(30, 33), name__like='Anton%%').order_by(id='desc')\n\nquery2 = table['person'].filter(id=2).join(\n Join(table['address'], 'id', 'ref_address')\n).join(\n LeftJoin(table['employees'], 'ref_person', 'id').join(\n Join(table['company'], 'id', 'ref_company').join(\n Join(table['address'], 'id', 'ref_address', 'compony_addr')\n ).filter(registration__between=('2020-01-02', '2020-01-06'))\n )\n).order_by(age='desc')\n\nquery3 = table['person'].filter(id=3).join(\n LeftJoin(table['employees'], 'ref_person', 'id')\n)\n```\n\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0411\u0414.\n```python\nres = query1.get()\nres = query2.get()\nres = query3.get()\n```\n\u0422\u0435\u043f\u0435\u0440\u044c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b \u0437\u0430\u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u043a\u0435\u0448\u0430.\n```python\nres = query1.get()\nres = query2.get()\nres = query3.get()\n```\n\n\u041d\u043e \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435? \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0438\u0437 \u0411\u0414, \u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0443 \u043d\u0430\u0441 \u043e\u0441\u0442\u0430\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0435 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c\u0438. \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0411\u0414 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434\u044b \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u0435.\n\n```python\n# \u0432\u0441\u0442\u0430\u0432\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0432 \u0411\u0414\ntable['address'].insert([dict(\n street='123',\n building=777\n)])\n# \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0432 \u0411\u0414\ntable['address'].filter(id=1).update(building=11)\n# \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0411\u0414\ntable['address'].filter(id=1).delete()\n```\n\u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u0435\u0448 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 `query1` \u0438 `query2` \u0431\u0443\u0434\u0443\u0442 \u043e\u0447\u0438\u0449\u0435\u043d\u044b, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.\n\u0422\u0430\u043a\u0436\u0435 \u0437\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u0447\u0442\u043e \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0432 \u0411\u0414 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u043b\u043e\u0432\u0430\u0440\u0435\u0439. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043e\u0434\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0411\u0414 \u0437\u0430 \u0440\u0430\u0437.\n\n\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043d\u043e\u0432\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0411\u0414.\n```python\nres = query1.get()\nres = query2.get()\n```\n\n\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0411\u0414, \u043d\u043e \u0432\u044b \u0436\u0435\u043b\u0430\u0435\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432 \u043a\u0435\u0448\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 `address` \u0431\u044b\u043b\u0438 \u043e\u0447\u0438\u0449\u0435\u043d\u044b, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a:\n```python\ntable['address'].delete_cache_table()\n```\n\n\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043d\u043e\u0432\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0411\u0414.\n```python\nres = query1.get()\nres = query2.get()\n```\n\n## \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u0435\u0448\u0435\u043c.\n\n> \u041d\u0435 \u043f\u044b\u0442\u0430\u0439\u0442\u0435\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u0435\u0448\u0443, \u0435\u0441\u043b\u0438 \u043e\u043d \u0443 \u0432\u0430\u0441 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d. \u042d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u043e\u0448\u0438\u0431\u043a\u0435.\n\n\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441.\n```python\n# \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\nquery = table['person'].join(\n Join(table['address'], 'id', 'ref_address')\n).filter(age__between=(30, 33), name__like='Anton%%').order_by(id='desc')\nquery.get() # \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443\nres = query.cache.get() # \u043f\u043e\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0438\u0437 \u043a\u0435\u0448\u0430\n# \u043b\u0438\u0431\u043e\nres = query.get() # \u0435\u0441\u043b\u0438 \u043a\u0435\u0448 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\nprint(res)\n\"\"\" \n[{'person.id': 3, 'person.login': 'geg', 'person.name': 'Anton 3', 'person.ref_address': 3, 'person.age': 33, 'address.id': 3, 'address.street': '\u0413\u0440\u0438\u043d\u0432\u0438\u0447', 'address.building': 12}, \n{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30, 'address.id': 2, 'address.street': '\u041d\u0430\u0443\u043c\u043e\u0432\u0430', 'address.building': 33}, \n{'person.id': 1, 'person.login': 'ant', 'person.name': 'Anton 1', 'person.ref_address': 1, 'person.age': 31, 'address.id': 1, 'address.street': '\u041f\u0443\u0448\u043a\u0438\u043d\u0430', 'address.building': 10}]\n\"\"\"\n```\n\n\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0430\u0448\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043a\u0435\u0448\u0435. \u041d\u043e \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u0443\u0447\u0435\u0442\u043e\u0432 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u043a\u0435\u0448\u0430?\n\n```python\n# \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0432\u044b\u0431\u043e\u0440\u043a\u0435. \n# \u0412 \u0444\u0438\u043b\u044c\u0442\u0440\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u0433\u043e\u0435 \u0440\u0430\u0432\u0435\u043d\u0441\u0442\u0432\u043e \u043f\u043e\u043b\u0435\u0439.\nres = query.cache.filter({'person.id': 1}).get()\n# \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044e.\nquery.cache.filter({'person.id': 1}).update({'person.name': 'Tony 1', 'person.age': 32})\n# \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043a\u0435\u0448.\nquery.cache.insert({\n 'person.id': 6, \n 'person.login': 'qqq', \n 'person.name': 'Anton 6', \n 'person.ref_address': 0, \n 'person.age': 0,\n 'address.id': 6,\n 'address.street': 'ytutyu',\n 'address.building': 567\n})\n# \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u0438\u0437 \u043a\u0435\u0448\u0430.\nquery.cache.filter({'person.id': 6}).delete()\n```\n\n\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 \u043a\u0435\u0448 \u043d\u0435 \u0432\u043b\u0435\u0447\u0435\u0442 \u0437\u0430 \u0441\u043e\u0431\u043e\u0439 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0411\u0414. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b \u0441\u0430\u043c\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0411\u0414 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0438\u0445 \u0432 \u043a\u0435\u0448\u0435, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0441\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c \u043a\u0435\u0448.\n\n\u041c\u044b \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u0437\u0430\u043f\u0438\u0441\u044c \u0441 \u0418\u0414 9 \u0431\u044b\u043b\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0430. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c: \n```python\nquery_9 = table['person'].join(\n Join(table['address'], 'id', 'ref_address')\n).filter(id=9)\nres: list = query_9.get()\n# \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0431\u043d\u043e\u0432\u0438\u043c \u043d\u0430\u0448 \u043a\u0435\u0448 \u0438\u0437 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430.\nquery.cache.filter({'person.id': 9}).update(**res[0])\n```\n\n\u0417\u0430\u043f\u0440\u043e\u0441 query_9 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d. \u0414\u0430\u0432\u0430\u0439 \u0441\u0431\u0440\u043e\u0441\u0438 \u043a\u0435\u0448 \u043f\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0443.\n```python\nquery_9.delete_cache_query()\n```\n\n\u0414\u043b\u044f \u043e\u0447\u0438\u0449\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043a\u0435\u0448\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435:\n```python\ntable.clear_cache()\n```\n\n## \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0411\u0414 \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435.\n\n\u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439. \u041d\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0411\u0414 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442\u044c \u043f\u043e \u0434\u0440\u0443\u0433\u043e\u043c\u0443, \u043a \u043d\u0438\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c `await`.\n\n\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 `TablesAsync`.\n```python\nfrom query_tables import TablesAsync\nfrom query_tables.cache import RedisConnect, AsyncRedisCache\nfrom query_tables.db import (\n AsyncSQLiteQuery, \n DBConfigPg, \n AsyncPostgresQuery\n)\n\nsqlite_async = AsyncSQLiteQuery(tests_dir / 'test_db.db')\n\npostgres_async = AsyncPostgresQuery(\n DBConfigPg('localhost', 'test', 'postgres', 'postgres')\n)\n\ntable = TablesAsync(sqlite_async, non_expired=True)\nawait table.init()\n# \u0438\u043b\u0438 \u0442\u0430\u043a\ntable = TablesAsync(postgres_async, non_expired=True)\nawait table.init()\n# \u0438\u043b\u0438 \u0442\u0430\u043a\nredis = AsyncRedisCache(RedisConnect())\ntable = TablesAsync(postgres_async, cache=redis)\nawait table.init()\n\n```\n\n\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0411\u0414.\n```python\nres1 = await table['person'].filter(id=2).get()\nres2 = await table['person'].filter(id=4).join(\n Join(table['employees'], 'ref_person', 'id')\n).get()\n\nquery = table['person'].filter(id=4).join(\n LeftJoin(table['employees'], 'ref_person', 'id')\n)\nres3 = await query.get()\n\nawait table['person'].insert([dict(\n login='tt',\n name='Ton',\n ref_address=1,\n age=55\n)])\n\nawait table['person'].filter(id=9).update(login='ant2', age=32)\nawait table['person'].filter(id=9).delete()\n```\n\n## \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c \u0441 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u043c \u043a\u0435\u0448\u0435\u043c.\n\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u0434\u043e\u0441\u0442\u0443\u043f\u043a\u0430 \u043a \u0434\u0430\u043d\u043d\u044b\u043c \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u0435\u0448\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f. \u041d\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043a\u0430 \u043a \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u043a\u0435\u0448\u0443 \u0431\u044b\u043b \u0438\u0437\u043c\u0435\u043d\u0435\u043d.\n\n\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 `TablesAsync`.\n```python\nfrom query_tables import TablesAsync\nfrom query_tables.cache import RedisConnect, AsyncRedisCache\nfrom query_tables.db import (\n DBConfigPg, \n AsyncPostgresQuery\n)\n\npostgres_async = AsyncPostgresQuery(\n DBConfigPg('localhost', 'test', 'postgres', 'postgres')\n)\n\nredis = AsyncRedisCache(RedisConnect())\ntable = TablesAsync(postgres_async, cache=redis)\nawait table.init()\n\n```\n\n\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043a\u0435\u0448\u0435.\n```python\n# \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\nquery = table['person'].join(\n Join(table['address'], 'id', 'ref_address')\n).filter(age__between=(30, 33), name__like='Anton%%').order_by(id='desc')\nawait query.get() # \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u0438\u0437 \u0411\u0414\nres = await query.cache.get() # \u043f\u043e\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0438\u0437 \u043a\u0435\u0448\u0430\n# \u043b\u0438\u0431\u043e\nres = await query.get() # \u0435\u0441\u043b\u0438 \u043a\u0435\u0448 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\nprint(res)\n\"\"\" \n[{'person.id': 3, 'person.login': 'geg', 'person.name': 'Anton 3', 'person.ref_address': 3, 'person.age': 33, 'address.id': 3, 'address.street': '\u0413\u0440\u0438\u043d\u0432\u0438\u0447', 'address.building': 12}, \n{'person.id': 2, 'person.login': 'mix', 'person.name': 'Anton 2', 'person.ref_address': 2, 'person.age': 30, 'address.id': 2, 'address.street': '\u041d\u0430\u0443\u043c\u043e\u0432\u0430', 'address.building': 33}, \n{'person.id': 1, 'person.login': 'ant', 'person.name': 'Anton 1', 'person.ref_address': 1, 'person.age': 31, 'address.id': 1, 'address.street': '\u041f\u0443\u0448\u043a\u0438\u043d\u0430', 'address.building': 10}]\n\"\"\"\n\n# \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043a\u0435\u0448\u0435 \u043f\u043e id\nawait query.cache.filter({'person.id': 1}).update({'person.name': 'Tony 1', 'person.age': 32})\n\n# \u0432\u0441\u0442\u0430\u0432\u043a\u0430 \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u043a\u0435\u0448\nawait query.cache.insert({\n\t'person.id': 6, \n\t'person.login': 'qqq', \n\t'person.name': 'Anton 6', \n\t'person.ref_address': 0, \n\t'person.age': 0,\n\t'address.id': 6,\n\t'address.street': 'ytutyu',\n\t'address.building': 567\n})\n\n# \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u043a\u0435\u0448\u0430\nawait query.cache.filter({'person.id': 6}).delete()\n\n# \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u0438\u0437 \u043a\u0435\u0448\u0430\nawait query.delete_cache_query()\n\n# \u043e\u0447\u0438\u0449\u0435\u043d\u0438\u0435 \u043a\u0435\u0448\u0430\nawait table.clear_cache()\n```\n\n## \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u044b\u0440\u044b\u0445 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.\n\n\u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u043a\u0430\u043a \u0432\u0430\u0448 \u0437\u0430\u043f\u0440\u043e\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u0438\u0437 \u043a\u0435\u0448\u0430.\n\u0414\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u044b\u0440\u044b\u0445 sql \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043c\u0435\u0442\u043e\u0434 `query` \u0441\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0439 sql \u0437\u0430\u043f\u0440\u043e\u0441\u0430.\n\n```python\nfrom query_tables import Tables\nfrom query_tables.db import DBConfigPg, PostgresQuery\nfrom query_tables.cache import RedisCache, RedisConnect\n\npostgres = PostgresQuery(\n DBConfigPg('localhost', 'test', 'postgres', 'postgres')\n)\nconnect = RedisConnect() # \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 \u0440\u0435\u0434\u0438\u0441\u043e\u043c\nredis_cache = RedisCache(connect)\ntables = Tables(postgres, cache=redis_cache)# \u043a\u0435\u0448 redis\n\n# \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u043a\u043e\u0440\u0442\u0435\u0436\u0435\u0439\nrows = tables.query('select * from person')\n```\n\n\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u0436\u0435 \u0432\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0431\u044b \u0435\u0433\u043e \u0437\u0430\u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \n```python\nquery = 'select * from person'\nrows = tables.query(query, cache=True)\n```\n\u042d\u0442\u043e \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0411\u0414 \u0438 \u0441\u0440\u0430\u0437\u0443 \u0438\u0445 \u043a\u0435\u0448\u0438\u0440\u0443\u0435\u0442 \u043f\u043e sql \u0437\u0430\u043f\u0440\u043e\u0441\u0443.\n\n\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0437 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043a\u0435\u0448\u0430:\n```python\nrows = tables.query(query, cache=True)\n```\n\n\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c \u0432\u044b \u0437\u043d\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u0431\u044b\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0438 \u0432\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0431\u044b \u0441\u043d\u043e\u0432\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0445 \u0438\u0437 \u0411\u0414 \u0432 \u043a\u0435\u0448.\n\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0444\u043b\u0430\u0433 `delete_cache`. \u042d\u0442\u043e \u0443\u0434\u0430\u043b\u0438\u0442 \u0441\u0442\u0430\u0440\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043a\u0435\u0448\u0430.\n\n```python\nrows = tables.query(query, cache=True, delete_cache=True)\n```\n\n\u0415\u0441\u043b\u0438 \u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043a\u0435\u0448\u0430 \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443. \n```python\nrows = tables.query(query, delete_cache=True)\n```\n\n\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0437 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0411\u0414:\n```python\nrows = tables.query(query, cache=True)\n```\n\n\u0414\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c `await`:\n```python\nfrom query_tables import TablesAsync\nfrom query_tables.cache import RedisConnect, AsyncRedisCache\nfrom query_tables.db import (\n DBConfigPg, \n AsyncPostgresQuery\n)\n\npostgres_async = AsyncPostgresQuery(\n DBConfigPg('localhost', 'test', 'postgres', 'postgres')\n)\n\nredis = AsyncRedisCache(RedisConnect())\ntable = TablesAsync(postgres_async, cache=redis)\nawait table.init()\nquery = 'select * from person'\nrows = await tables.query(query)\n```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435 \u0431\u0435\u0437 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043a\u0435\u0448\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 (CORMless).",
"version": "1.11.23",
"project_urls": {
"Github": "https://github.com/AntonGlyzin/query_tables",
"Read the docs": "https://query-tables.readthedocs.io",
"Releases": "https://github.com/AntonGlyzin/query_tables/releases"
},
"split_keywords": [
"cache",
"orm",
"sql",
"table",
"redis",
"postgres",
"sqlite",
"asyncio",
"python"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "6d7ddf81e081dbbc62379a3fb007159ba163b91fc24bfb0d39aa84c842b35b69",
"md5": "2ff06175e65a48473e83bbed75122712",
"sha256": "99c61db2b24a3a978c6c9f715c18a9426d0226be3bece9362690e1995db35acb"
},
"downloads": -1,
"filename": "query_tables-1.11.23-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2ff06175e65a48473e83bbed75122712",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 37387,
"upload_time": "2025-08-09T04:28:42",
"upload_time_iso_8601": "2025-08-09T04:28:42.999976Z",
"url": "https://files.pythonhosted.org/packages/6d/7d/df81e081dbbc62379a3fb007159ba163b91fc24bfb0d39aa84c842b35b69/query_tables-1.11.23-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-09 04:28:42",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "AntonGlyzin",
"github_project": "query_tables",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "query-tables"
}