Skip to content
This repository was archived by the owner on May 17, 2024. It is now read-only.

Commit 7e65475

Browse files
authored
Merge pull request #17 from datafold/dev
Docs and REPL
2 parents ffc4afe + 0117d8b commit 7e65475

File tree

9 files changed

+151
-17
lines changed

9 files changed

+151
-17
lines changed

README.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ It consists of -
1212

1313
It is comparable to other libraries such as SQLAlchemy or PyPika, in terms of API and intended audience. However there are several notable ways in which it is different.
1414

15+
## Overview
16+
1517
### Built for performance
1618

1719
- Multi-threaded by default -
@@ -31,11 +33,13 @@ This feature can be also used to inform the query-builder, either as an alternat
3133

3234
The schema is used for validation when building expressions, making sure the names are correct, and that the data-types align.
3335

36+
(Still WIP)
37+
3438
### Multi-database access
3539

3640
Sqeleton is designed to work with several databases at the same time. Its API abstracts away as many implementation details as possible.
3741

38-
Databases we support:
42+
Databases we fully support:
3943

4044
- PostgreSQL >=10
4145
- MySQL
@@ -51,11 +55,28 @@ Databases we support:
5155
- DuckDB >=0.6
5256
- SQLite (coming soon)
5357

54-
55-
### Documentation
58+
## Documentation
5659

5760
[Read the docs!](https://sqeleton.readthedocs.io)
5861

62+
Or jump straight to the [introduction](https://sqeleton.readthedocs.io/en/latest/intro.html).
63+
64+
### Install
65+
66+
Install using pip:
67+
68+
```bash
69+
pip install sqeleton
70+
```
71+
72+
It is recommended to install the driver dependencies using pip's `[]` syntax:
73+
74+
```bash
75+
pip install 'sqeleton[mysql, postgresql]'
76+
```
77+
78+
Read more in [install / getting started.](https://sqeleton.readthedocs.io/en/latest/install.html)
79+
5980
### Basic usage
6081

6182
```python

docs/conn_editor.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Connection Editor
2+
3+
A common complaint among new users was the difficulty in setting up the connections.
4+
5+
Connection URLs are admittedly confusing, and editing `.toml` files isn't always straight-forward either.
6+
7+
To ease this initial difficulty, we added a `textual`-based TUI tool to sqeleton, that allows users to edit configuration files and test the connections while editing them.
8+
9+
## Install
10+
11+
This tool needs `textual` to run. You can install it using:
12+
13+
```bash
14+
pip install 'sqeleton[tui]'
15+
```
16+
17+
Make sure you also have drivers for whatever database connection you're going to edit!
18+
19+
## Run
20+
21+
Once everything is installed, you can run the editor with the following command:
22+
23+
```bash
24+
sqeleton conn-editor <conf_path.toml>
25+
```
26+
27+
Example:
28+
29+
```bash
30+
sqeleton conn-editor ~/dbs.toml
31+
```
32+
33+
The available actions and hotkeys will be listed in the status bar.
34+
35+
Note: using the connection editor will delete comments and reformat the file!
36+
37+
We recommend backing up the configuration file before editing it.

docs/index.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
:caption: API Reference
44
:hidden:
55

6+
install
67
intro
78
supported-databases
9+
conn_editor
810
python-api
911

1012
Sqeleton
@@ -26,8 +28,10 @@ For more information, `See our README <https://github.com/datafold/sqeleton#read
2628
Resources
2729
---------
2830

31+
- :doc:`install`
2932
- :doc:`intro`
3033
- :doc:`supported-databases`
34+
- :doc:`conn_editor`
3135
- :doc:`python-api`
3236
- Source code (git): `<https://github.com/datafold/sqeleton>`_
3337

docs/install.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Install / Get started
2+
3+
Sqeleton can be installed using pip:
4+
5+
```
6+
pip install sqeleton
7+
```
8+
9+
## Database drivers
10+
11+
To ensure that the database drivers are compatible with sqeleton, we recommend installing them along with sqeleton, using pip's `[]` syntax:
12+
13+
- `pip install 'sqeleton[mysql]'`
14+
15+
- `pip install 'sqeleton[postgresql]'`
16+
17+
- `pip install 'sqeleton[snowflake]'`
18+
19+
- `pip install 'sqeleton[presto]'`
20+
21+
- `pip install 'sqeleton[oracle]'`
22+
23+
- `pip install 'sqeleton[trino]'`
24+
25+
- `pip install 'sqeleton[clickhouse]'`
26+
27+
- `pip install 'sqeleton[vertica]'`
28+
29+
- For BigQuery, see: https://pypi.org/project/google-cloud-bigquery/
30+
31+
_Some drivers have dependencies that cannot be installed using `pip` and still need to be installed manually._
32+
33+
34+
It is also possible to install several databases at once. For example:
35+
36+
```bash
37+
pip install 'sqeleton[mysql, postgresql]'
38+
```
39+
40+
Note: Some shells use `"` for escaping instead, like:
41+
42+
```bash
43+
pip install "sqeleton[mysql, postgresql]"
44+
```
45+
46+
## Connection editor
47+
48+
Sqeleton provides a TUI connection editor, that can be installed using:
49+
50+
```bash
51+
pip install 'sqeleton[tui]'
52+
```
53+
54+
Read more [here](conn_editor.md).
55+
56+
## What's next?
57+
58+
Read the [introduction](intro.md) and start coding!

docs/intro.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,12 +440,12 @@ from sqeleton.abcs.mixins import AbstractMixin_NormalizeValue, AbstractMixin_Ran
440440

441441
connect = sqeleton.connect.load_mixins(AbstractMixin_NormalizeValue)
442442
ddb = connect("duckdb://:memory:")
443-
print(ddb.dialect.normalize_boolean("bool", None) == "bool::INTEGER::VARCHAR")
443+
print(ddb.dialect.normalize_boolean("bool", None))
444444
# Outputs:
445445
# bool::INTEGER::VARCHAR
446446
```
447447

448-
Each database is already aware of the available mixin implementation, because it was defined with the `MIXINS` attribute. We're only using the abstract mixins to select the mixins we want to use.
448+
Each database is already aware of the available mixin implementations, because it was defined with the `MIXINS` attribute. We're only using the abstract mixins to select the mixins we want to use.
449449

450450
#### List of mixins
451451

@@ -463,6 +463,10 @@ List of available abstract mixins:
463463

464464
- `AbstractMixin_TimeTravel` - Only snowflake & bigquery
465465

466+
More will be added in the future.
467+
468+
Note that it's still possible to use user-defined mixins that aren't on this list.
469+
466470
#### Unimplemented Mixins
467471

468472
Trying to load a mixin that isn't implemented by all databases, will fail:

sqeleton/databases/base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ def _normalize_table_path(self, path: DbPath) -> DbPath:
487487
def parse_table_name(self, name: str) -> DbPath:
488488
return parse_table_name(name)
489489

490-
def _query_cursor(self, c, sql_code: str):
490+
def _query_cursor(self, c, sql_code: str) -> QueryResult:
491491
assert isinstance(sql_code, str), sql_code
492492
try:
493493
c.execute(sql_code)
@@ -499,7 +499,7 @@ def _query_cursor(self, c, sql_code: str):
499499
# logger.error(f'Caused by SQL: {sql_code}')
500500
raise
501501

502-
def _query_conn(self, conn, sql_code: Union[str, ThreadLocalInterpreter]) -> list:
502+
def _query_conn(self, conn, sql_code: Union[str, ThreadLocalInterpreter]) -> QueryResult:
503503
c = conn.cursor()
504504
callback = partial(self._query_cursor, c)
505505
return apply_query(callback, sql_code)
@@ -542,7 +542,7 @@ def set_conn(self):
542542
except Exception as e:
543543
self._init_error = e
544544

545-
def _query(self, sql_code: Union[str, ThreadLocalInterpreter]):
545+
def _query(self, sql_code: Union[str, ThreadLocalInterpreter]) -> QueryResult:
546546
r = self._queue.submit(self._query_in_worker, sql_code)
547547
return r.result()
548548

sqeleton/databases/bigquery.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
)
2020
from ..abcs import Compilable
2121
from ..queries import this, table, SKIP, code
22-
from .base import BaseDialect, Database, import_helper, parse_table_name, ConnectError, apply_query
22+
from .base import BaseDialect, Database, import_helper, parse_table_name, ConnectError, apply_query, QueryResult
2323
from .base import TIMESTAMP_PRECISION_POS, ThreadLocalInterpreter, Mixin_RandomSample
2424

2525

@@ -161,16 +161,18 @@ def _query_atom(self, sql_code: str):
161161
from google.cloud import bigquery
162162

163163
try:
164-
res = list(self._client.query(sql_code))
164+
result = self._client.query(sql_code).result()
165+
columns = [c.name for c in result.schema]
166+
rows = list(result)
165167
except Exception as e:
166168
msg = "Exception when trying to execute SQL code:\n %s\n\nGot error: %s"
167169
raise ConnectError(msg % (sql_code, e))
168170

169-
if res and isinstance(res[0], bigquery.table.Row):
170-
res = [tuple(self._normalize_returned_value(v) for v in row.values()) for row in res]
171-
return res
171+
if rows and isinstance(rows[0], bigquery.table.Row):
172+
rows = [tuple(self._normalize_returned_value(v) for v in row.values()) for row in rows]
173+
return QueryResult(rows, columns)
172174

173-
def _query(self, sql_code: Union[str, ThreadLocalInterpreter]):
175+
def _query(self, sql_code: Union[str, ThreadLocalInterpreter]) -> QueryResult:
174176
return apply_query(self._query_atom, sql_code)
175177

176178
def close(self):

sqeleton/repl.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ def repl(uri):
4747
help()
4848
continue
4949
try:
50-
schema = db.query_table_schema((table_name,))
50+
path = db.parse_table_name(table_name)
51+
print('->', path)
52+
schema = db.query_table_schema(path)
5153
except Exception as e:
5254
logging.error(e)
5355
else:

sqeleton/utils.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Iterable, Iterator, MutableMapping, Union, Any, Sequence, Dict, Hashable, TypeVar, TYPE_CHECKING
1+
from typing import Iterable, Iterator, MutableMapping, Union, Any, Sequence, Dict, Hashable, TypeVar, TYPE_CHECKING, List
22
from abc import abstractmethod
33
from weakref import ref
44
import math
@@ -251,6 +251,12 @@ def __lt__(self, other):
251251
return NotImplemented
252252
return self._str < other._str
253253

254+
def __eq__(self, other):
255+
if not isinstance(other, type(self)):
256+
return NotImplemented
257+
return self._str == other._str
258+
259+
254260
def new(self, *args, **kw):
255261
return type(self)(*args, **kw, max_len=self._max_len)
256262

@@ -266,7 +272,7 @@ def number_to_human(n):
266272
return "{:.0f}{}".format(n / 10 ** (3 * millidx), millnames[millidx])
267273

268274

269-
def split_space(start, end, count):
275+
def split_space(start, end, count) -> List[int]:
270276
size = end - start
271277
assert count <= size, (count, size)
272278
return list(range(start, end, (size + 1) // (count + 1)))[1 : count + 1]

0 commit comments

Comments
 (0)