diff --git a/docs/source/creating_queries.rst b/docs/source/creating_queries.rst new file mode 100644 index 0000000000000000000000000000000000000000..9d9ad0f4322aca14512f0eab6f278b8d1926fd21 --- /dev/null +++ b/docs/source/creating_queries.rst @@ -0,0 +1,525 @@ +Creating Queries +**************** + +The main purpose of ``py-dbcn`` is to create some kind of database queries +to read from or manipulate one or more database. +The syntax is meant to be as intuitive as possible, with the package taking +care of as much work as it can, behind the scenes. + +For example, when providing quotes to a value, the quote type does not matter. +``Py-dbcn`` will automatically convert the quotes to the expected type, +depending on the database used. All of [", ', `] will be treated equally. + +For now, the ``py-dbcn`` package only provides basic database calls, and these +are provided on the :ref:`database <database querying>`, +:ref:`table <table querying>`, and :ref:`record <record querying>` levels. + + +.. note:: + + When applicable, these interface methods provide a result that makes sense + for the given query type. The intention is to allow further Pythonic logic + to be run, if desired. If nothing else, it allows for verifying the query + result in whatever way desired. + + For methods that return ``None``, it is safe to assume the query will either + succeed, or return a Python error. + + +.. important:: + + While not fully implemented yet, the intention is to also have full, dynamic + validation of all values provided to these interface methods. + + In the future, the ``py-dbcn`` package will do what it can to auto-format + and auto-correct common mistakes in provided syntax. When it can't correct, + it will return a descriptive error that explains the problem, before the + query ever hits the database itself. + + +Database Querying +================= + +All database-level querying is done via the ``connector.database`` interface. + + +SHOW Existing Databases +----------------------- + +``connector.database.show()`` + +:return: A list of all found databases. + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + list_of_databases = connector.database.show() + + # Print list of databases. + for database in list_of_databases: + print(database) + + +Display current Database +------------------------ + +``connector.database.select()`` + +``connector.database.current()`` + +:return: Str of currently selected database name. + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + current_db = connector.database.select() + + # Print name of current database. + print(current_db) + + +USE a different Database +------------------------ + +``connector.database.use(db_name)`` + +:param db_name: Name of database to change to. + +:return: None + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + connector.database.use('test_db') + + +CREATE a new Database +--------------------- + +``connector.database.create(db_name)`` + +:param db_name: Name of database to create. + +:return: None + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + connector.database.create('a_new_database') + + +DELETE an existing Database +--------------------------- + +``connector.database.delete(db_name)`` + +``connector.database.drop(db_name)`` + +:param db_name: Name of database to delete. + +:return: None + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + connector.database.drop('an_old_database') + + +Table Querying +============== + +All table-level querying is done via the ``connector.table`` interface. + + +SHOW Existing Tables +-------------------- + +``connector.tables.show()`` + +:return: A list of all found tables in currently selected database. + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + list_of_tables = connector.tables.show() + + # Print list of tables. + for table in list_of_tables: + print(table) + + +DESCRIBE existing Table +----------------------- + +``connector.tables.describe(table_name)`` + +:param table_name: Name of table to describe. + +:return: A list of all columns in table, including several useful attributes. + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + list_of_columns = connector.tables.describe('my_table') + + # Print list of table columns. + for column in columns: + print(column) + + +CREATE a new Table +------------------ + +``connector.tables.create(table_name, table_columns)`` + +:param table_name: Name of table to create. + +:param table_columns: The columns to provide the new table. + +:return: None + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + connector.tables.create( + 'a_new_table', + """ + id INT NOT NULL AUTO_INCREMENT, + name VARCHAR(100), + description VARCHAR(100), + PRIMARY KEY ( id ) + """, + ) + + +UPDATE an existing Table +------------------------ + +``connector.tables.update(table_name, table_columns)`` + +``connector.tables.modify(table_name, table_columns)`` + +:param table_name: Name of table to create. + +:param modify_clause: The type of modification to make. IE: One of + [ADD, DROP, MODIFY]. + +:param column_clause: The columns to modify. + +:return: None + + +TODO: Create examples and expand modify logic. Maybe not fully implemented? + + +DROP an existing Table +------------------------ + +``connector.tables.drop(table_name)`` + +``connector.tables.delete(table_name)`` + +:param table_name: Name of table to remove. + +:return: None + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + connector.tables.drop('old_table') + + +COUNT records present in table +------------------------------ + +``connector.tables.count(table_name)`` + +:param table_name: Name of table to count records of. + +:return: A count of records present in table. + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + record_count = connector.tables.count('my_table') + + # Print number of records found. + print(record_count) + + +Record Querying +=============== + +All record-level querying is done via the ``connector.record`` interface. + + +SELECT a set of Records +----------------------- + +``connector.records.select(table_name, select_clause=None, where_clause=None)`` + +:param table_name: Name of table to select records from. + +:param select_clause: Optional clause to limit the number of columns that return + for each record. If not provided, ``*`` wildcard selector + is used. + + Can be in format of a list, or comma separated str. + +:param where_clause: Optional clause to limit number of records selected. If + not provided, then all records are selected. + +:return: A list of all returned records. + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + # In this case, we only pull "id", "name", and "description" columns from + # all records with an "id" less than 500. + results = connector.records.select( + 'my_table', + select_clause='id, name, description', + where_clause='where id < 500', + ) + + # Print list of pulled records. + for record in results: + print(record) + + +INSERT new Records +------------------ + +``connector.records.insert(table_name, values_clause, columns_clause=None)`` + +:param table_name: Name of table to select records from. + +:param values_clause: Clause to provide values for new record. + +:param columns_clause: Optional clause to indicate what columns are being + provided, as well as what order they're in. If not + present, then query will assume all columns are being + provided, in the order they were originally added to the + table. + +:return: TODO: Honestly unsure of what this provides. Double check. + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + # In this case, we insert a record by giving a "name" and "description". + # We omit "id" so it will be auto-provided (assuming it's a field with + # some kind of reliable default value). + connector.records.insert( + 'my_table', + values_clause='"Regal Red Towel", "Red towel with yellow embroidery."', + columns_clause='name, description', + ) + + +UPDATE existing Records +----------------------- + +``connector.records.update(table_name, values_clause, where_clause)`` + +:param table_name: Name of table to update records within. + +:param values_clause: Clause to provide values for updated record. + +:param where_clause: Clause to limit number of records selected. + + Due to the nature of this query, where clause is mandatory + BUT if an empty string is provided, then the query will + still select all records. + +:return: TODO: Honestly unsure of what this provides. Double check. + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + # In this case, we insert a record by giving a "name" and "description". + # We omit "id" so it will be auto-provided (assuming it's a field with + # some kind of reliable default value). + connector.records.update( + 'my_table', + values_clause='description = "Refurbished item"', + where_clause='name = "Refurbished"', + ) + + +DELETE existing Records +----------------------- + +``connector.records.delete(table_name, where_clause)`` + +:param table_name: Name of table to delete records from. + +:param where_clause: Clause to limit number of records selected. + + Due to the nature of this query, where clause is mandatory + BUT if an empty string is provided, then the query will + still select all records. + +:return: TODO: Honestly unsure of what this provides. Double check. + + +Example: + +.. code-block:: python + + # Import MySQL connector. + from py_dbcn.connectors import MysqlDbConnector + + ... + + # Initialize MySQL database connection. + connector = MysqlDbConnector(host, port, user, password, db_name) + + # Run query. + connector.records.delete( + 'my_table', + where_clause='name = "Refurbished"', + ) diff --git a/docs/source/index.rst b/docs/source/index.rst index 9ca947077562a6e5733de45d5f539b871111994a..02eaa03fc7f425aeae28009564ce805268cb9ccb 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,21 +1,38 @@ -.. py-dbcn documentation master file, created by - sphinx-quickstart on Wed Jun 22 12:23:27 2022. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - - Pythonic Database Connector =========================== The **Pythonic Database Connector** package (aka **py-dbcn**) is a connector to allow Pythonic interaction with multiple database types. +The main original purpose of this package is to allow for an easier way to +read in and migrate data between databases, such as during a database upgrade. + +The idea is to create a package that allows quick and easy interfacing to +the database of choice, using a simple Pythonic interface. +No need to necessarily know the quirks of each database type, as long as you +have a general idea of what database logic is required. +This package will handle the details from there. + +Due to being written in Python, this package allows having a easily-repeatable +set of database calls, which can be thoroughly tested and examined via the +standard Python library, to ensure maximum database integrity at every step of +the way. + + +.. note:: + Currently, this is only implemented for `MySQL <https://www.mysql.com/>`_ + and `PostgreSQL <https://www.postgresql.org/>`_. + + There are plans to at least implement this for + `SqLite <https://www.sqlite.org/>`_ as well. + .. toctree:: :maxdepth: 2 :caption: Contents: quickstart + creating_queries configuration .. toctree:: diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst index 64a248b3fcaecd7be43940e3b0d1a868b17f9175..9192df5fd7480d68e2afdb4c7086eb1c963084af 100644 --- a/docs/source/quickstart.rst +++ b/docs/source/quickstart.rst @@ -1,5 +1,72 @@ Quickstart ********** -Testing for setting up read-the-docs for a package. -Quickstart to be written later. +1. Load up your VirtualEnvironment of choice and run: + + .. code-block:: python + + pip install py-dbcn + + + Alternatively, add ``py-dbcn`` to your respective project + requirements file, and then follow the standard package installation method + for your project + (`requirements.txt <https://pip.pypa.io/en/stable/user_guide/#requirements-files>`_, + `pipenv <https://pipenv.pypa.io/en/latest/>`_, + `poetry <https://python-poetry.org/docs/>`_, etc). + +2. Create a new Python project (or load an existing one) and establish one or + more database connections: + + .. code-block:: python + + # Here we initialize a single MySQL connection. + from py_dbcn.connectors import MysqlDbConnector + + # Import config values from some other file. + from .settings import mysql_config + + ... + + connector = MysqlDbConnector( + mysql_config['db_host'], + mysql_config['db_port'], + mysql_config['db_user'], + mysql_config['db_user_password'], + mysql_config['db_name'], + ) + + .. important:: + With the above code, we're specifically importing the database settings + from some outside location. In this case, we import these values as + a dictionary format. + + Depending on who can access this project and how it's stored, it's often + much more secure to avoid committing database settings to the project. + + Instead, add some file to the project's ``.gitignore`` and read in + config values from there. It can also be helpful to make an + ``example_config.py`` file, to show the expected format of how these + settings should be provided (but without committing the actual database + credentials). + +3. Install optional packages for extra functionality. + + This package offers support for the + `colorama <https://pypi.org/project/colorama/>`_ Python package. + + Colorama is not necessary to use ``py-dbcn``, but adding it will provide + helpful coloring output, to help separate what kind of calls are being made. + +4. Run database queries as desired. See <link-here>. + + .. note:: + + Closing the database is not necessary, as ``py-dbcn`` will automatically + take care of it on program termination. + + However, if desired, you can still manually close the database + connection mid-program. + + The ``py-dbcn`` library also has no built-in limitations. You are free + to open and close as many simultaneous connections as you wish.