# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['pg_database', 'pg_database.tests']

package_data = \
{'': ['*']}

install_requires = \
['GeoAlchemy2',
 'frozendict>=2.0,<3.0',
 'psycopg2-binary>=2.7.7,<3.0.0',
 'sqlalchemy>=1.3.0,<1.4.0']

setup_kwargs = {
    'name': 'pg-database-utils',
    'version': '0.8.2',
    'description': 'A collection of performant parsing utilities',
    'long_description': '# pg-database-utils\n\n[![Build Status](https://api.travis-ci.com/consbio/pg-database-utils.png?branch=main)](https://app.travis-ci.com/github/consbio/pg-database-utils)\n[![Coverage Status](https://coveralls.io/repos/github/consbio/pg-database-utils/badge.svg?branch=main)](https://coveralls.io/github/consbio/pg-database-utils?branch=main)\n\nA suite of utilities for PostgreSQL database queries and operations built on sqlalchemy.\n\nThis library includes support for:\n1. `TSVECTOR`, `JSON` and `JSONB` indexes (for PostgreSQL versions 9.5+)\n2. Generated columns (for PostgreSQL versions 12+)\n3. Optional Django database configuration for Django projects\n\nIt also includes:\n1. Helpers to make most common DDL queries more readable\n2. Performant functions for querying JSON and TSVECTOR columns\n3. Support for `SELECT INTO` queries from existing tables and/or `VALUES` clauses\n4. Support for `UPDATE` queries that require application logic\n\n\n## Installation\nInstall with:\n```bash\npip install pg-database-utils\n```\n\n## Configuration\n\nThis project is designed to make configuration easy.\nIf you already have database connections defined in Django, then you can reuse them;\notherwise, you can configure your own without having Django as a dependency.\n\n### To configure with Django\n\nIf you want to use the "default" database, **no configuration is required**.\n\nIf you want to specify a particular Django database to read settings from:\n1. Create a JSON configuration file with the database name:\n```python\n{\n    "django-db-key": "other",               # To override DATABASES["default"]\n    "connect-args": {"sslmode": "require"}  # To override DATABASES["<db_name>"]["OPTIONS"]\n}\n```\n2. Set the `DATABASE_CONFIG_JSON` environment variable to point to the location of the file\n\n**Note**: "django-db-key" takes precedence over all other database connection settings in the JSON file.\nIf you specify a Django database, those database connection settings will be used.\n\n### To configure without Django\n\n1. Create a JSON configuration file with at least the required settings (i.e. `database-name`):\n```python\n{\n    "database-name": "required",     # Name of the database to query\n    "database-engine": "optional",   # Defaults to postgres\n    "database-host": "optional",     # Defaults to 127.0.0.1\n    "database-port": "optional",     # Defaults to 5432\n    "database-user": "optional",     # Defaults to postgres\n    "database-password": "optional"  # For trusted users like postgres\n}\n```\n2. Set the `DATABASE_CONFIG_JSON` environment variable to point to the location of the file\n\n### Additional configuration with or without Django\n\nAdditional configuration options include:\n```python\n{\n    "connect-args": {"sslmode": "require"},  # Defaults to postgres settings, "prefer" by default\n    "date-format": "optional",               # Defaults to "%Y-%m-%d"\n    "timestamp-format": "optional",          # Defaults to "%Y-%m-%d %H:%M:%S"\n    "pooling-args": {                        # To override sqlalchemy pooling config\n        "max_overflow": 0,                   # Defaults to 10 connections beyond pool size\n        "pool_recycle": 60,                  # Defaults to no timeout (-1) in seconds\n        "pool_size": 20,                     # Defaults to 5 connections\n        "pool_timeout": 30                   # Defaults to 30 seconds\n     }\n}\n```\n\n**Note**: "date-format" and "timestamp-format" must be compatible with the formatting configured in PostgreSQL.\n\n\n## Usage\n\nThis library is designed to make common database operations easy and readable,\nso most of the utility functions are designed to work with either strings or `sqlalchemy` objects as parameters.\n\n### Schema utilities\n\n* Creating and relating tables\n```python\nfrom pg_database import schema\n\nmy_table = schema.create_table(\n    "my_table",\n    dropfirst=True,\n    index_cols={"id": "unique"},\n    id="int", name="int", addr="text", geom="bytea", deleted="bool"\n)\nschema.create_index(my_table, "name", index_op="unique")\n\nschema.create_table("other_table", id="int", my_table_id="int", val="text")\nschema.create_foreign_key("other_table", "my_table_id", "my_table.id")\n```\n* Altering tables\n```python\nfrom pg_database import schema\n\nschema.alter_column_type("my_table", "name", "text")\nschema.create_index("my_table", "name", index_op="to_tsvector")\n\nschema.create_column("my_table", "json_col", "jsonb", checkfirst=True)\nschema.create_index("my_table", "json_col", index_op="json_full")\n\n# These steps require the postgis extension\nschema.alter_column_type("my_table", "geom", "geometry", using="geom::geometry(Polygon,4326)")\nschema.create_index("my_table", "geom", index_op="spatial")\n```\n* Dropping database objects\n```python\nfrom pg_database import schema\n\nall_tables = schema.get_metadata().tables\nother_table = all_tables["other_table"]\n\nschema.drop_foreign_key(other_table, "other_table_my_table_id_fkey")\nschema.drop_index("my_table", index_name="my_table_json_col_json_full_idx")\nschema.drop_table("my_table")\nschema.drop_table(other_table)\n```\n\n### SQL utilities\n\n* Inserting rows\n```python\nimport json\nfrom datetime import datetime, timedelta\nfrom pg_database import sql\n\ncreate_date = datetime.now()\n\nsql.select_into(\n    "new_table",\n    [\n        (1, "one", {}, create_date),\n        (2, "two", {}, create_date),\n        (3, "three", {}, create_date)\n    ],\n    "id,val,json,created",\n    "int,text,jsonb,date"\n)\n```\n* Updating rows\n```python\nfrom pg_database import sql\n\ndef update_row(row):\n    row = list(row)\n    pk, val, created, jval = row[0], row[1], row[2], row[3]\n    row[1] = f"{pk} {val} first batch"\n    row[2] = created + timedelta(days=1)\n    row[3] = {"id": pk, "val": val, "batch": "first"}\n    return row\n\nsql.update_rows("new_table", "id", "val,created,json", update_row, batch_size=3)\n```\n* Querying rows\n```python\nfrom pg_database import sql, schema\n\n# Reduce database queries by sending a sqlalchemy table\nall_tables = schema.get_metadata().tables\nnew_table = all_tables["new_table"]\n\nschema.create_index(new_table, "json", index_op="json_path")\nschema.create_index(new_table, "val", index_op="to_tsvector")\n\nsql.query_json_keys(new_table, "json", {"batch": "first"})\nsql.query_tsvector_columns("new_table", "val", "batch first")\n```\n* Values clause for `INSERT`s or `SELECT INTO`, with custom connection arguments at execution time\n```python\nfrom datetime import datetime\nfrom sqlalchemy import column\nfrom sqlalchemy.sql import Insert, Select\nfrom pg_database import sql, schema\n\n# Prepare data, column names, column types and table name\n\ncreate_date = datetime.now()\n\nvalues_data = [\n    (1, "one", {}, True, create_date),\n    (2, "two", {}, False, create_date),\n    (3, "three", {}, 0, create_date)\n]\nvalues_names = ["id", "val", "json", "boolean", "created"]\nvalues_types = ["int", "text", "jsonb", "bool", "date"]\nvalues_table = "values_table"\n\n# SELECT INTO to create a new table from raw values using sslmode==require\n\nselect_vals = sql.Values(values_names, values_types, *values_data)\nselect_into = sql.SelectInto([column(c) for c in values_names], values_table)\nwith schema.get_engine(connect_args={"sslmode": "require"}).connect() as conn:\n    conn.execute(select_into.select_from(select_vals).execution_options(autocommit=True))\n\n# INSERT INTO to add new records from raw values using custom pooling args\n\nexisting_table = schema.get_metadata().tables[values_table]\n\ninsert_vals = sql.Values(values_names, values_types, *values_data)\ninsert_from = Select([column(c) for c in values_names]).select_from(insert_vals)\ninsert_into = Insert(existing_table).from_select(names=values_names, select=insert_from)\nwith schema.get_engine(pooling_args={"pool_size": 20, "max_overflow": 0}).connect() as conn:\n    conn.execute(insert_into.execution_options(autocommit=True))\n```\n',
    'author': 'dharvey-consbio',
    'author_email': 'dani.harvey@consbio.org',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/consbio/pg-database-utils/',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.6,<4.0',
}


setup(**setup_kwargs)
