Skip to content

Commit 235e072

Browse files
committed
fixes #12
1 parent cba13c9 commit 235e072

File tree

5 files changed

+273
-15
lines changed

5 files changed

+273
-15
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
_proc/
22
db_dc.py
3+
*-client_wal_index
4+
*-shm
5+
*-wal
36
*.sqlite
47
*.db
58
sidebar.yml

fastlite/_modidx.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
'doc_host': 'https://AnswerDotAI.github.io',
66
'git_url': 'https://github.com/AnswerDotAI/fastlite',
77
'lib_path': 'fastlite'},
8-
'syms': { 'fastlite.core': { 'fastlite.core.Database.q': ('core.html#database.q', 'fastlite/core.py'),
8+
'syms': { 'fastlite.core': { 'fastlite.core.Database.create': ('core.html#database.create', 'fastlite/core.py'),
9+
'fastlite.core.Database.q': ('core.html#database.q', 'fastlite/core.py'),
910
'fastlite.core.Database.t': ('core.html#database.t', 'fastlite/core.py'),
1011
'fastlite.core.Database.v': ('core.html#database.v', 'fastlite/core.py'),
1112
'fastlite.core.Table.__call__': ('core.html#table.__call__', 'fastlite/core.py'),
1213
'fastlite.core.Table.__str__': ('core.html#table.__str__', 'fastlite/core.py'),
1314
'fastlite.core.Table.c': ('core.html#table.c', 'fastlite/core.py'),
14-
'fastlite.core.Table.dataclass': ('core.html#table.dataclass', 'fastlite/core.py'),
1515
'fastlite.core.View.__call__': ('core.html#view.__call__', 'fastlite/core.py'),
1616
'fastlite.core.View.__str__': ('core.html#view.__str__', 'fastlite/core.py'),
1717
'fastlite.core.View.c': ('core.html#view.c', 'fastlite/core.py'),
@@ -37,6 +37,7 @@
3737
'fastlite.core._TablesGetter.__dir__': ('core.html#_tablesgetter.__dir__', 'fastlite/core.py'),
3838
'fastlite.core._ViewsGetter': ('core.html#_viewsgetter', 'fastlite/core.py'),
3939
'fastlite.core._ViewsGetter.__dir__': ('core.html#_viewsgetter.__dir__', 'fastlite/core.py'),
40+
'fastlite.core._dataclass': ('core.html#_dataclass', 'fastlite/core.py'),
4041
'fastlite.core._edge': ('core.html#_edge', 'fastlite/core.py'),
4142
'fastlite.core._get_flds': ('core.html#_get_flds', 'fastlite/core.py'),
4243
'fastlite.core._row': ('core.html#_row', 'fastlite/core.py'),

fastlite/core.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
__all__ = ['all_dcs', 'create_mod', 'diagram']
55

66
# %% ../nbs/00_core.ipynb 3
7-
from dataclasses import field, make_dataclass, fields, Field, is_dataclass, MISSING
7+
from dataclasses import dataclass, field, make_dataclass, fields, Field, is_dataclass, MISSING
88
from typing import Any,Union,Optional
9+
from inspect import get_annotations
910

1011
from fastcore.utils import *
1112
from fastcore.xml import highlight
1213
from fastcore.xtras import hl_md, dataclass_src
1314
from sqlite_minutils.db import *
15+
import types
1416

1517
try: from graphviz import Source
1618
except ImportError: pass
@@ -76,13 +78,14 @@ def _get_flds(tbl):
7678
return [(k, v|None, field(default=tbl.default_values.get(k,None)))
7779
for k,v in tbl.columns_dict.items()]
7880

79-
@patch
80-
def dataclass(self:Table, store=True, suf='')->type:
81+
def _dataclass(self:Table, store=True, suf='')->type:
8182
"Create a `dataclass` with the types and defaults of this table"
8283
res = make_dataclass(self.name.title()+suf, _get_flds(self))
8384
if store: self.cls = res
8485
return res
8586

87+
Table.dataclass = _dataclass
88+
8689
# %% ../nbs/00_core.ipynb 30
8790
def all_dcs(db, with_views=False, store=True, suf=''):
8891
"dataclasses for all objects in `db`"
@@ -124,7 +127,39 @@ def __dir__(self): return self.db.view_names()
124127
@patch(as_prop=True)
125128
def v(self:Database): return _ViewsGetter(self)
126129

127-
# %% ../nbs/00_core.ipynb 50
130+
# %% ../nbs/00_core.ipynb 47
131+
@patch
132+
def create(
133+
self: Database,
134+
cls=None, # Dataclass to create table from
135+
name=None, # Name of table to create
136+
pk='id', # Column(s) to use as a primary key
137+
foreign_keys=None, # Foreign key definitions
138+
defaults=None, # Database table defaults
139+
column_order=None, # Which columns should come first
140+
not_null=None, # Columns that should be created as ``NOT NULL``
141+
hash_id=None, # Column to be used as a primary key using hash
142+
hash_id_columns=None, # Columns used when calculating hash
143+
extracts=None, # Columns to be extracted during inserts
144+
if_not_exists=False, # Use `CREATE TABLE IF NOT EXISTS`
145+
replace=False, # Drop and replace table if it already exists
146+
ignore=True, # Silently do nothing if table already exists
147+
transform=False, # If table exists transform it to fit schema
148+
strict=False, # Apply STRICT mode to table
149+
):
150+
"Create table from `cls`, default name to snake-case version of class name"
151+
mk_dataclass(cls)
152+
if name is None: name = camel2snake(cls.__name__)
153+
typs = {o.name: o.type for o in fields(cls)}
154+
res = self.create_table(
155+
name, typs, defaults=defaults,
156+
pk=pk, foreign_keys=foreign_keys, column_order=column_order, not_null=not_null,
157+
hash_id=hash_id, hash_id_columns=hash_id_columns, extracts=extracts, transform=transform,
158+
if_not_exists=if_not_exists, replace=replace, ignore=ignore, strict=strict)
159+
res.cls = cls
160+
return res
161+
162+
# %% ../nbs/00_core.ipynb 55
128163
def _edge(tbl):
129164
return "\n".join(f"{fk.table}:{fk.column} -> {fk.other_table}:{fk.other_column};"
130165
for fk in tbl.foreign_keys)
@@ -142,7 +177,7 @@ def _tnode(tbl):
142177
</table>"""
143178
return f"{tbl.name} [label=<{res}>];\n"
144179

145-
# %% ../nbs/00_core.ipynb 51
180+
# %% ../nbs/00_core.ipynb 56
146181
def diagram(tbls, ratio=0.7, size="10", neato=False, render=True):
147182
layout = "\nlayout=neato;\noverlap=prism;\noverlap_scaling=0.5;""" if neato else ""
148183
edges = "\n".join(map(_edge, tbls))

nbs/00_core.ipynb

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@
3232
"outputs": [],
3333
"source": [
3434
"#| export\n",
35-
"from dataclasses import field, make_dataclass, fields, Field, is_dataclass, MISSING\n",
35+
"from dataclasses import dataclass, field, make_dataclass, fields, Field, is_dataclass, MISSING\n",
3636
"from typing import Any,Union,Optional\n",
37+
"from inspect import get_annotations\n",
3738
"\n",
3839
"from fastcore.utils import *\n",
3940
"from fastcore.xml import highlight\n",
4041
"from fastcore.xtras import hl_md, dataclass_src\n",
4142
"from sqlite_minutils.db import *\n",
43+
"import types\n",
4244
"\n",
4345
"try: from graphviz import Source\n",
4446
"except ImportError: pass"
@@ -366,12 +368,13 @@
366368
" return [(k, v|None, field(default=tbl.default_values.get(k,None)))\n",
367369
" for k,v in tbl.columns_dict.items()]\n",
368370
"\n",
369-
"@patch\n",
370-
"def dataclass(self:Table, store=True, suf='')->type:\n",
371+
"def _dataclass(self:Table, store=True, suf='')->type:\n",
371372
" \"Create a `dataclass` with the types and defaults of this table\"\n",
372373
" res = make_dataclass(self.name.title()+suf, _get_flds(self))\n",
373374
" if store: self.cls = res\n",
374-
" return res"
375+
" return res\n",
376+
"\n",
377+
"Table.dataclass = _dataclass"
375378
]
376379
},
377380
{
@@ -734,6 +737,105 @@
734737
"dv.AccaDaccaAlbums()"
735738
]
736739
},
740+
{
741+
"cell_type": "code",
742+
"execution_count": null,
743+
"metadata": {},
744+
"outputs": [],
745+
"source": [
746+
"#| exports\n",
747+
"@patch\n",
748+
"def create(\n",
749+
" self: Database,\n",
750+
" cls=None, # Dataclass to create table from\n",
751+
" name=None, # Name of table to create\n",
752+
" pk='id', # Column(s) to use as a primary key\n",
753+
" foreign_keys=None, # Foreign key definitions\n",
754+
" defaults=None, # Database table defaults\n",
755+
" column_order=None, # Which columns should come first\n",
756+
" not_null=None, # Columns that should be created as ``NOT NULL``\n",
757+
" hash_id=None, # Column to be used as a primary key using hash\n",
758+
" hash_id_columns=None, # Columns used when calculating hash\n",
759+
" extracts=None, # Columns to be extracted during inserts\n",
760+
" if_not_exists=False, # Use `CREATE TABLE IF NOT EXISTS`\n",
761+
" replace=False, # Drop and replace table if it already exists\n",
762+
" ignore=True, # Silently do nothing if table already exists\n",
763+
" transform=False, # If table exists transform it to fit schema\n",
764+
" strict=False, # Apply STRICT mode to table\n",
765+
"):\n",
766+
" \"Create table from `cls`, default name to snake-case version of class name\"\n",
767+
" mk_dataclass(cls)\n",
768+
" if name is None: name = camel2snake(cls.__name__)\n",
769+
" typs = {o.name: o.type for o in fields(cls)}\n",
770+
" res = self.create_table(\n",
771+
" name, typs, defaults=defaults,\n",
772+
" pk=pk, foreign_keys=foreign_keys, column_order=column_order, not_null=not_null,\n",
773+
" hash_id=hash_id, hash_id_columns=hash_id_columns, extracts=extracts, transform=transform,\n",
774+
" if_not_exists=if_not_exists, replace=replace, ignore=ignore, strict=strict)\n",
775+
" res.cls = cls\n",
776+
" return res"
777+
]
778+
},
779+
{
780+
"cell_type": "markdown",
781+
"metadata": {},
782+
"source": [
783+
"The class you pass to `create` is converted to a dataclass where any fields missing a default are defaulted to `None`."
784+
]
785+
},
786+
{
787+
"cell_type": "code",
788+
"execution_count": null,
789+
"metadata": {},
790+
"outputs": [
791+
{
792+
"data": {
793+
"text/plain": [
794+
"Cat(id=1, name=None, age=None, city='Unknown')"
795+
]
796+
},
797+
"execution_count": null,
798+
"metadata": {},
799+
"output_type": "execute_result"
800+
}
801+
],
802+
"source": [
803+
"class Cat: id: int; name: str; age: int; city: str = \"Unknown\"\n",
804+
"cats = db.create(Cat)\n",
805+
"Cat(1)"
806+
]
807+
},
808+
{
809+
"cell_type": "code",
810+
"execution_count": null,
811+
"metadata": {},
812+
"outputs": [
813+
{
814+
"name": "stdout",
815+
"output_type": "stream",
816+
"text": [
817+
"CREATE TABLE [cat] (\n",
818+
" [id] INTEGER PRIMARY KEY,\n",
819+
" [name] TEXT,\n",
820+
" [age] INTEGER,\n",
821+
" [city] TEXT\n",
822+
")\n"
823+
]
824+
}
825+
],
826+
"source": [
827+
"print(cats.schema)"
828+
]
829+
},
830+
{
831+
"cell_type": "code",
832+
"execution_count": null,
833+
"metadata": {},
834+
"outputs": [],
835+
"source": [
836+
"db.t.cat.drop()"
837+
]
838+
},
737839
{
738840
"cell_type": "markdown",
739841
"metadata": {},

0 commit comments

Comments
 (0)