data3 1.0.2
SQLite3 Wrapper for Python
Requires Python: >=3.7

This module is meant to be used in small to medium scale applications and makes SQLite3 Read and Write functions python.
Changing every DataBase, Table and Row object to classes.

# Quickstart
```cmd
pip install data3
```
1. To get the entire DataBase use:
   ```py
   import data3
   
   with data.open() as db:
     pass
   ```
   Alternatively, you can use the following code to get just one table:
   ```py
   with data.open(table="YourTable") as table:
      pass
   ```
   Data3 will automatically open and close connections for you.
2. Index a table with `databaseObject["YourTable"]`
3. Read data with `table.get()`, you can narrow down your search by using `table.get(column=value)` or use `table.first()` to get only the first value
4. Adding/updating/removing data works as following: `table.add(column=value, column=value...)`, `table.update(column=value)(column=value, column=value...)`, `table.remove(column=value)`.
5. By adding, finding or updating data you will be returned a `rowObject` which you can index with columns to find one value, you can use `rowObject.pk` to get just the primaryKey, it can also be converted to a Dict or you can edit your row by using `rowObject["column"] = value` or `rowObject(column=value, column=value)`

# Example
```py
import data3

with data3.open(table="matches") as table:
    # the database object will only connect to the database once a database.execute has been used, which is good for optemisation and allows you to have big functions without having the database open the entire time
    # if you're using the table parameter to specify a certain table, this still applies, however it will also connect once you reference a table attribute as it needs to read that from the database
    # in short, you're not connected here

    for row in table.find():
        # but here you are connected
        row["started"] = True
    
    print(table.find(searchParams = data3.searchParams(
        selection="*",
        order = "id",
        limit = 3,
        offset = 2,
    )))

    table.update(5)(started = False) # here no column is specified for the value of 5, data3 will look for a primary key column or alternatively the first column

    table(id = 99, started = False) # the default function of table.__call__ (calling the table) is to insert a value and will behave the same as table.add

    print(table.first())

    with table.pause():
        # here you're once again disconnected
        print("Free from the database.")

    # with table.pause will not reconnect you after, table.pause is purely for syntax and backwards compatability
    # doing the following would do the exact same thing
    table.stop()
    print("Free from the database.")

    table.remove(3) # now you're connected again, as table.remove() triggers database.execute which makes sure we're connected to the database

@data3.using("table", table="matches") # the first argument "argument" will be what is returned to your function as the database or table object
def foo1(table):
    return table.first(90)

@data3.using # you don't need to call the decorator first as it will recognise if the first argument is a function and wrap it with the default arguments
def foo2(db): # the default "argument" is "db"
    return db.getTables()

print(
    foo1(),
    foo2()
)
```  

# Edit default values
```py
import data3

# These are the default values and you can edit them accordingly
data3.path = './'
data3.defaultFile = "data"
data3.fileExtension = ".db"
data3.defaultTimeout = 10

# This is the default onError function, which you can modify
def onError(error, cmd):
    print(f"[Error\t] {error}\n[input\t] {cmd}")
data3.onError = onError
```