DefPixel 0.1.0__3-py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- DefPixel/DataAccessObject/Configuration.py +15 -0
- DefPixel/DataAccessObject/Connection.py +25 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Configuration.py +16 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Connection.py +96 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Constraint.py +9 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Constraints/ForeignKey.py +16 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Constraints/PrimaryKey.py +15 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Constraints/Unique.py +25 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Constraints/__init__.py +11 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Context.py +36 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Cursor.py +87 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Executors/Create.py +115 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Executors/Delete.py +35 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Executors/Drop.py +34 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Executors/Get.py +24 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Executors/Insert.py +59 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Executors/Select.py +109 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Executors/Update.py +34 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Executors/__init__.py +19 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Expr.py +42 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Exprs/Alias.py +20 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Exprs/Is.py +29 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Exprs/__init__.py +13 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Filters/Compare.py +149 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Filters/Operator.py +26 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Filters/String.py +23 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Filters/__init__.py +30 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Function.py +15 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Functions/Common.py +34 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Functions/Condition.py +21 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Functions/__init__.py +16 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Index.py +23 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Joins/FullOuter.py +19 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Joins/Inner.py +19 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Joins/Join.py +31 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Joins/LeftOuter.py +19 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Joins/RightOuter.py +19 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Joins/__init__.py +13 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Mapping.py +303 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Orders/Ascend.py +24 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Orders/Descend.py +24 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Orders/__init__.py +9 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Session.py +37 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Type.py +75 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Types/Binary.py +28 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Types/DateTime.py +42 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Types/Numeric.py +49 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Types/String.py +28 -0
- DefPixel/DataAccessObject/Implements/Sqlite/Types/__init__.py +34 -0
- DefPixel/DataAccessObject/Implements/Sqlite/__init__.py +39 -0
- DefPixel/DataAccessObject/Implements/__init__.py +1 -0
- DefPixel/DataAccessObject/Properties/Database/Context.py +33 -0
- DefPixel/DataAccessObject/Properties/Database/Cursor.py +27 -0
- DefPixel/DataAccessObject/Properties/Database/Database.py +48 -0
- DefPixel/DataAccessObject/Properties/Database/Executor.py +38 -0
- DefPixel/DataAccessObject/Properties/Database/Executors.py +31 -0
- DefPixel/DataAccessObject/Properties/Database/Fetch.py +37 -0
- DefPixel/DataAccessObject/Properties/Database/Filter.py +21 -0
- DefPixel/DataAccessObject/Properties/Database/Run.py +39 -0
- DefPixel/DataAccessObject/Properties/Database/Session.py +36 -0
- DefPixel/DataAccessObject/Properties/Database/__init__.py +25 -0
- DefPixel/DataAccessObject/Properties/Dataclass.py +25 -0
- DefPixel/DataAccessObject/Properties/Document/Document.py +36 -0
- DefPixel/DataAccessObject/Properties/Document/__init__.py +7 -0
- DefPixel/DataAccessObject/Properties/Index/Index.py +48 -0
- DefPixel/DataAccessObject/Properties/Index/__init__.py +7 -0
- DefPixel/DataAccessObject/Properties/KeyValue/KeyValue.py +44 -0
- DefPixel/DataAccessObject/Properties/KeyValue/__init__.py +7 -0
- DefPixel/DataAccessObject/Properties/__init__.py +15 -0
- DefPixel/DataAccessObject/__init__.py +9 -0
- DefPixel/Validator/Pattern.py +36 -0
- DefPixel/Validator/Patterns/Array.py +30 -0
- DefPixel/Validator/Patterns/Common.py +92 -0
- DefPixel/Validator/Patterns/Compare.py +180 -0
- DefPixel/Validator/Patterns/Condition.py +60 -0
- DefPixel/Validator/Patterns/DataObject.py +85 -0
- DefPixel/Validator/Patterns/DateTime.py +111 -0
- DefPixel/Validator/Patterns/Number.py +43 -0
- DefPixel/Validator/Patterns/Object.py +150 -0
- DefPixel/Validator/Patterns/Size.py +110 -0
- DefPixel/Validator/Patterns/String.py +85 -0
- DefPixel/Validator/Patterns/Type.py +350 -0
- DefPixel/Validator/Patterns/__init__.py +137 -0
- DefPixel/Validator/Validate.py +29 -0
- DefPixel/Validator/Validator.py +30 -0
- DefPixel/Validator/__init__.py +11 -0
- DefPixel/__init__.py +0 -0
- defpixel-0.1.0.dist-info/METADATA +114 -0
- defpixel-0.1.0.dist-info/RECORD +92 -0
- defpixel-0.1.0.dist-info/WHEEL +6 -0
- defpixel-0.1.0.dist-info/licenses/LICENSE +674 -0
- defpixel-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from abc import ABCMeta, abstractmethod
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
'Configuration'
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Configuration(metaclass=ABCMeta):
|
|
11
|
+
"""Configuration Interface"""
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def __init__(self, *args, **kwargs):
|
|
15
|
+
raise NotImplementedError('{} must be implemented __init__'.format(self.__class__.__name__))
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from .Configuration import Configuration
|
|
4
|
+
|
|
5
|
+
from abc import ABCMeta, abstractmethod
|
|
6
|
+
|
|
7
|
+
__all__ = (
|
|
8
|
+
'Connection'
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Connection(metaclass=ABCMeta):
|
|
13
|
+
"""Connection Interface"""
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def __init__(self, conf: Configuration):
|
|
17
|
+
raise NotImplementedError('{} must be implemented __init__ method'.format(self.__class__.__name__))
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def connect(self):
|
|
21
|
+
raise NotImplementedError('{} must be implemented connect method'.format(self.__class__.__name__))
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def close(self):
|
|
25
|
+
raise NotImplementedError('{} must be implemented close method'.format(self.__class__.__name__))
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from DefPixel.DataAccessObject import Configuration as BaseConfiguration
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
'Configuration'
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Configuration(BaseConfiguration):
|
|
11
|
+
"""Configuration Class for Sqlite"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, path: str, autocommit: bool = False):
|
|
14
|
+
self.path = path
|
|
15
|
+
self.autocommit = autocommit
|
|
16
|
+
return
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from sqlite3 import (
|
|
4
|
+
Row,
|
|
5
|
+
connect,
|
|
6
|
+
)
|
|
7
|
+
from DefPixel.DataAccessObject import Connection as BaseConnection
|
|
8
|
+
from DefPixel.DataAccessObject.Properties.Database import (
|
|
9
|
+
Database,
|
|
10
|
+
Run,
|
|
11
|
+
)
|
|
12
|
+
from .Cursor import Cursor
|
|
13
|
+
from .Session import Session
|
|
14
|
+
|
|
15
|
+
__all__ = (
|
|
16
|
+
'Connection',
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Connection(BaseConnection, Database, Run):
|
|
21
|
+
"""SQLite connection with explicit lifecycle and transaction management."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, conf):
|
|
24
|
+
self.conf = conf
|
|
25
|
+
self.connection = None
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
def connect(self):
|
|
29
|
+
if self.connection is not None:
|
|
30
|
+
raise RuntimeError('The SQLite connection is already open')
|
|
31
|
+
self.connection = connect(
|
|
32
|
+
self.conf.path,
|
|
33
|
+
isolation_level=None if self.conf.autocommit else 'DEFERRED',
|
|
34
|
+
check_same_thread=False,
|
|
35
|
+
)
|
|
36
|
+
self.connection.row_factory = Row
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
def active(self):
|
|
40
|
+
if self.connection is None:
|
|
41
|
+
raise RuntimeError('The SQLite connection is not open')
|
|
42
|
+
return self.connection
|
|
43
|
+
|
|
44
|
+
def close(self):
|
|
45
|
+
if self.connection is not None:
|
|
46
|
+
self.connection.close()
|
|
47
|
+
self.connection = None
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
def begin(self):
|
|
51
|
+
self.active().execute('BEGIN')
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
def execute(
|
|
55
|
+
self,
|
|
56
|
+
sql,
|
|
57
|
+
*args,
|
|
58
|
+
):
|
|
59
|
+
return self.cursor().execute(sql, *args)
|
|
60
|
+
|
|
61
|
+
def executes(
|
|
62
|
+
self,
|
|
63
|
+
sql,
|
|
64
|
+
*args,
|
|
65
|
+
):
|
|
66
|
+
return self.cursor().executes(sql, *args)
|
|
67
|
+
|
|
68
|
+
def run(
|
|
69
|
+
self,
|
|
70
|
+
executor,
|
|
71
|
+
filter=None,
|
|
72
|
+
fetch=None,
|
|
73
|
+
):
|
|
74
|
+
cursor = self.cursor()
|
|
75
|
+
try:
|
|
76
|
+
return cursor.run(
|
|
77
|
+
executor,
|
|
78
|
+
filter=filter,
|
|
79
|
+
fetch=fetch,
|
|
80
|
+
)
|
|
81
|
+
finally:
|
|
82
|
+
cursor.close()
|
|
83
|
+
|
|
84
|
+
def cursor(self):
|
|
85
|
+
return Cursor(self.active().cursor())
|
|
86
|
+
|
|
87
|
+
def session(self):
|
|
88
|
+
return Session(self.active())
|
|
89
|
+
|
|
90
|
+
def commit(self):
|
|
91
|
+
self.active().commit()
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
def rollback(self):
|
|
95
|
+
self.active().rollback()
|
|
96
|
+
return
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from ..Constraint import Constraint
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
'ForeignKey'
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ForeignKey(Constraint):
|
|
11
|
+
def __init__(self, cols, reference, referenceCols):
|
|
12
|
+
self.cols = cols if isinstance(cols, (tuple, list)) else [cols]
|
|
13
|
+
self.reference = reference
|
|
14
|
+
self.referenceCols = referenceCols if isinstance(referenceCols, (tuple, list)) else [referenceCols]
|
|
15
|
+
return
|
|
16
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from ..Constraint import Constraint
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
'PrimaryKey'
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class PrimaryKey(Constraint):
|
|
11
|
+
def __init__(self, cols, autoincrement=False):
|
|
12
|
+
self.cols = cols if isinstance(cols, (tuple, list)) else [cols]
|
|
13
|
+
self.autoincrement = autoincrement
|
|
14
|
+
return
|
|
15
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from ..Constraint import Constraint
|
|
4
|
+
|
|
5
|
+
from typing import Union, Sequence
|
|
6
|
+
|
|
7
|
+
__all__ = (
|
|
8
|
+
'Unique'
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Unique(Constraint):
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
name: str,
|
|
16
|
+
colexprs: Union[str, Sequence[str]],
|
|
17
|
+
expr: str = None,
|
|
18
|
+
notexists: bool = None,
|
|
19
|
+
):
|
|
20
|
+
self.name = name
|
|
21
|
+
self.colexprs = colexprs if isinstance(colexprs, (tuple, list)) else [colexprs]
|
|
22
|
+
self.expr = expr
|
|
23
|
+
self.notexists = notexists
|
|
24
|
+
return
|
|
25
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from DefPixel.DataAccessObject.Properties.Database import Context as BaseContext
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
'Context',
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Context(BaseContext):
|
|
11
|
+
"""Context exposing SQLite execution results."""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
cursor,
|
|
16
|
+
query=None,
|
|
17
|
+
):
|
|
18
|
+
self.cursor = cursor
|
|
19
|
+
self.statement = query
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
def rows(self):
|
|
23
|
+
return [dict(row) for row in self.cursor.fetchall()]
|
|
24
|
+
|
|
25
|
+
def row(self):
|
|
26
|
+
row = self.cursor.fetchone()
|
|
27
|
+
return dict(row) if row is not None else None
|
|
28
|
+
|
|
29
|
+
def count(self):
|
|
30
|
+
return self.cursor.connection.total_changes
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def query(self):
|
|
34
|
+
if self.statement is None:
|
|
35
|
+
raise RuntimeError('The executed query is not available in this context')
|
|
36
|
+
return self.statement
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from DefPixel.DataAccessObject.Properties.Database import (
|
|
4
|
+
Cursor as BaseCursor,
|
|
5
|
+
Executor,
|
|
6
|
+
Executors,
|
|
7
|
+
Fetch,
|
|
8
|
+
Run,
|
|
9
|
+
)
|
|
10
|
+
from .Context import Context
|
|
11
|
+
from .Mapping import inspect_model
|
|
12
|
+
|
|
13
|
+
__all__ = (
|
|
14
|
+
'Cursor',
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Cursor(BaseCursor, Run):
|
|
19
|
+
"""SQLite cursor supporting direct SQL and ORM execution."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, cursor):
|
|
22
|
+
self.cursor = cursor
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
def execute(
|
|
26
|
+
self,
|
|
27
|
+
sql,
|
|
28
|
+
*args,
|
|
29
|
+
):
|
|
30
|
+
self.cursor.execute(sql, args)
|
|
31
|
+
return Context(self.cursor, sql)
|
|
32
|
+
|
|
33
|
+
def executes(
|
|
34
|
+
self,
|
|
35
|
+
sql,
|
|
36
|
+
*args,
|
|
37
|
+
):
|
|
38
|
+
self.cursor.executemany(sql, args)
|
|
39
|
+
return Context(self.cursor, sql)
|
|
40
|
+
|
|
41
|
+
def run(
|
|
42
|
+
self,
|
|
43
|
+
executor,
|
|
44
|
+
filter=None,
|
|
45
|
+
fetch=None,
|
|
46
|
+
):
|
|
47
|
+
if fetch is not None:
|
|
48
|
+
inspect_model(fetch)
|
|
49
|
+
if isinstance(executor, Executor):
|
|
50
|
+
self.cursor.execute(executor.query, executor.args)
|
|
51
|
+
if isinstance(executor, Fetch):
|
|
52
|
+
return executor.fetch(
|
|
53
|
+
self,
|
|
54
|
+
filter=filter,
|
|
55
|
+
fetch=fetch,
|
|
56
|
+
)
|
|
57
|
+
return None
|
|
58
|
+
if isinstance(executor, Executors):
|
|
59
|
+
result = []
|
|
60
|
+
for statement in executor:
|
|
61
|
+
if not isinstance(statement, Executor):
|
|
62
|
+
raise TypeError('Executors must yield Executor objects')
|
|
63
|
+
value = self.run(
|
|
64
|
+
statement,
|
|
65
|
+
filter=filter,
|
|
66
|
+
fetch=fetch,
|
|
67
|
+
)
|
|
68
|
+
if isinstance(value, list):
|
|
69
|
+
result.extend(value)
|
|
70
|
+
elif value is not None:
|
|
71
|
+
result.append(value)
|
|
72
|
+
return result
|
|
73
|
+
raise TypeError('run requires an Executor or Executors object')
|
|
74
|
+
|
|
75
|
+
def rows(self):
|
|
76
|
+
return [dict(row) for row in self.cursor.fetchall()]
|
|
77
|
+
|
|
78
|
+
def row(self):
|
|
79
|
+
row = self.cursor.fetchone()
|
|
80
|
+
return dict(row) if row is not None else None
|
|
81
|
+
|
|
82
|
+
def count(self):
|
|
83
|
+
raise RuntimeError('SQLite query result row counts are not supported')
|
|
84
|
+
|
|
85
|
+
def close(self):
|
|
86
|
+
self.cursor.close()
|
|
87
|
+
return
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from dataclasses import MISSING
|
|
4
|
+
from DefPixel.DataAccessObject.Properties.Database import Executors
|
|
5
|
+
from ..Constraints import (
|
|
6
|
+
ForeignKey,
|
|
7
|
+
PrimaryKey,
|
|
8
|
+
Unique,
|
|
9
|
+
)
|
|
10
|
+
from ..Function import Function
|
|
11
|
+
from ..Index import Index
|
|
12
|
+
from ..Mapping import (
|
|
13
|
+
Statement,
|
|
14
|
+
identifier,
|
|
15
|
+
inspect_model,
|
|
16
|
+
)
|
|
17
|
+
from ..Expr import Expr
|
|
18
|
+
|
|
19
|
+
__all__ = (
|
|
20
|
+
'Create',
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Create(Executors):
|
|
25
|
+
"""Provide table, view, and index creation as individual execution statements."""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
o,
|
|
30
|
+
notexist=True,
|
|
31
|
+
):
|
|
32
|
+
mapping = inspect_model(o)
|
|
33
|
+
self.executors = []
|
|
34
|
+
if mapping.kind == 'view':
|
|
35
|
+
self.executors.append(Statement(
|
|
36
|
+
'CREATE VIEW {}{} AS {}'.format(
|
|
37
|
+
'IF NOT EXISTS ' if notexist else '',
|
|
38
|
+
identifier(mapping.name),
|
|
39
|
+
mapping.executor.query,
|
|
40
|
+
),
|
|
41
|
+
))
|
|
42
|
+
return
|
|
43
|
+
def column_name(name):
|
|
44
|
+
if name in mapping.columns:
|
|
45
|
+
return identifier(mapping.columns[name].key)
|
|
46
|
+
if name in {spec.key for spec in mapping.columns.values()}:
|
|
47
|
+
return identifier(name)
|
|
48
|
+
raise ValueError('Constraint column is not mapped: {}'.format(name))
|
|
49
|
+
keys = [item for item in mapping.constraints if isinstance(item, PrimaryKey)]
|
|
50
|
+
if len(keys) > 1:
|
|
51
|
+
raise ValueError('Multiple primary key definitions are not allowed')
|
|
52
|
+
auto = keys[0] if keys and keys[0].autoincrement else None
|
|
53
|
+
if auto is not None and len(auto.cols) != 1:
|
|
54
|
+
raise ValueError('AUTOINCREMENT requires a single INTEGER primary key')
|
|
55
|
+
definitions = []
|
|
56
|
+
for spec in mapping.columns.values():
|
|
57
|
+
definition = '{} {}'.format(identifier(spec.key), spec.typestr)
|
|
58
|
+
if auto is not None and column_name(auto.cols[0]) == identifier(spec.key):
|
|
59
|
+
if spec.typestr != 'INTEGER':
|
|
60
|
+
raise ValueError('AUTOINCREMENT requires an INTEGER column')
|
|
61
|
+
definition += ' PRIMARY KEY AUTOINCREMENT'
|
|
62
|
+
if not spec.null:
|
|
63
|
+
definition += ' NOT NULL'
|
|
64
|
+
if spec.coldef is not MISSING:
|
|
65
|
+
value = spec.coldef
|
|
66
|
+
if isinstance(value, Function):
|
|
67
|
+
definition += ' DEFAULT ({})'.format(value)
|
|
68
|
+
else:
|
|
69
|
+
definition += ' DEFAULT {}'.format(Expr.literal(spec.encode(value)))
|
|
70
|
+
definitions.append(definition)
|
|
71
|
+
for constraint in mapping.constraints:
|
|
72
|
+
if isinstance(constraint, PrimaryKey):
|
|
73
|
+
if auto is None:
|
|
74
|
+
definitions.append('PRIMARY KEY({})'.format(
|
|
75
|
+
', '.join(column_name(name) for name in constraint.cols),
|
|
76
|
+
))
|
|
77
|
+
elif isinstance(constraint, ForeignKey):
|
|
78
|
+
if len(constraint.cols) != len(constraint.referenceCols):
|
|
79
|
+
raise ValueError('Foreign key column counts do not match')
|
|
80
|
+
definitions.append('FOREIGN KEY({}) REFERENCES {}({})'.format(
|
|
81
|
+
', '.join(column_name(name) for name in constraint.cols),
|
|
82
|
+
identifier(constraint.reference),
|
|
83
|
+
', '.join(identifier(name) for name in constraint.referenceCols),
|
|
84
|
+
))
|
|
85
|
+
elif not isinstance(constraint, Unique):
|
|
86
|
+
raise TypeError('Unsupported SQLite constraint')
|
|
87
|
+
self.executors.append(Statement(
|
|
88
|
+
'CREATE TABLE {}{}({})'.format(
|
|
89
|
+
'IF NOT EXISTS ' if notexist else '',
|
|
90
|
+
identifier(mapping.name),
|
|
91
|
+
', '.join(definitions),
|
|
92
|
+
),
|
|
93
|
+
))
|
|
94
|
+
for index in tuple(
|
|
95
|
+
value for value in mapping.constraints if isinstance(value, Unique)
|
|
96
|
+
) + mapping.indexes:
|
|
97
|
+
if not isinstance(index, (Index, Unique)):
|
|
98
|
+
raise TypeError('Unsupported SQLite index')
|
|
99
|
+
self.executors.append(Statement(
|
|
100
|
+
'CREATE {}INDEX {}{} ON {}({}){}'.format(
|
|
101
|
+
'UNIQUE ' if isinstance(index, Unique) else '',
|
|
102
|
+
'IF NOT EXISTS ' if index.notexists else '',
|
|
103
|
+
identifier(index.name),
|
|
104
|
+
identifier(mapping.name),
|
|
105
|
+
', '.join(
|
|
106
|
+
column_name(value) if isinstance(value, str) else str(value)
|
|
107
|
+
for value in index.colexprs
|
|
108
|
+
),
|
|
109
|
+
' WHERE {}'.format(index.expr) if index.expr else '',
|
|
110
|
+
),
|
|
111
|
+
))
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
def __iter__(self):
|
|
115
|
+
return iter(self.executors)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from DefPixel.DataAccessObject.Properties.Database import Executor
|
|
4
|
+
from ..Mapping import (
|
|
5
|
+
identifier,
|
|
6
|
+
inspect_model,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = (
|
|
10
|
+
'Delete',
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Delete(Executor):
|
|
15
|
+
"""Delete query using an explicit table mapping."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, o):
|
|
18
|
+
self.mapping = inspect_model(o, 'table')
|
|
19
|
+
self.conds = ()
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
def where(self, *args):
|
|
23
|
+
self.conds = args
|
|
24
|
+
return self
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def query(self):
|
|
28
|
+
return 'DELETE FROM {}{}'.format(
|
|
29
|
+
identifier(self.mapping.name),
|
|
30
|
+
' WHERE ' + ' AND '.join(str(cond) for cond in self.conds) if self.conds else '',
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def args(self):
|
|
35
|
+
return ()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from DefPixel.DataAccessObject.Properties.Database import Executors
|
|
4
|
+
from ..Mapping import (
|
|
5
|
+
Statement,
|
|
6
|
+
identifier,
|
|
7
|
+
inspect_model,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = (
|
|
11
|
+
'Drop',
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Drop(Executors):
|
|
16
|
+
"""SQLite drops associated indexes when a table is dropped."""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
o,
|
|
21
|
+
exist=True,
|
|
22
|
+
):
|
|
23
|
+
mapping = inspect_model(o)
|
|
24
|
+
self.executors = [Statement(
|
|
25
|
+
'DROP {} {}{}'.format(
|
|
26
|
+
mapping.kind.upper(),
|
|
27
|
+
'IF EXISTS ' if exist else '',
|
|
28
|
+
identifier(mapping.name),
|
|
29
|
+
),
|
|
30
|
+
)]
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
def __iter__(self):
|
|
34
|
+
return iter(self.executors)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from .Select import Select
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
'Get',
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Get(Select):
|
|
11
|
+
"""Return the first result while preserving the existing Get interface."""
|
|
12
|
+
|
|
13
|
+
def fetch(
|
|
14
|
+
self,
|
|
15
|
+
cursor,
|
|
16
|
+
filter=None,
|
|
17
|
+
fetch=None,
|
|
18
|
+
):
|
|
19
|
+
rows = super().fetch(
|
|
20
|
+
cursor,
|
|
21
|
+
filter=filter,
|
|
22
|
+
fetch=fetch,
|
|
23
|
+
)
|
|
24
|
+
return rows[0] if rows else None
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from DefPixel.DataAccessObject.Properties.Database import (
|
|
4
|
+
Executor,
|
|
5
|
+
Fetch,
|
|
6
|
+
)
|
|
7
|
+
from ..Mapping import (
|
|
8
|
+
identifier,
|
|
9
|
+
inspect_model,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = (
|
|
13
|
+
'Insert',
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Insert(Executor, Fetch):
|
|
18
|
+
"""Map field names to columns and bind validated values."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, o):
|
|
21
|
+
self.mapping = inspect_model(o, 'table')
|
|
22
|
+
self.kwargs = {}
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
def values(self, **kwargs):
|
|
26
|
+
self.kwargs.update(self.mapping.values(kwargs))
|
|
27
|
+
return self
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def query(self):
|
|
31
|
+
if not self.kwargs:
|
|
32
|
+
return 'INSERT INTO {} DEFAULT VALUES RETURNING *'.format(
|
|
33
|
+
identifier(self.mapping.name),
|
|
34
|
+
)
|
|
35
|
+
return 'INSERT INTO {}({}) VALUES({}) RETURNING *'.format(
|
|
36
|
+
identifier(self.mapping.name),
|
|
37
|
+
', '.join(identifier(key) for key in self.kwargs),
|
|
38
|
+
', '.join(['?'] * len(self.kwargs)),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def args(self):
|
|
43
|
+
return tuple(self.kwargs.values())
|
|
44
|
+
|
|
45
|
+
def fetch(
|
|
46
|
+
self,
|
|
47
|
+
cursor,
|
|
48
|
+
filter=None,
|
|
49
|
+
fetch=None,
|
|
50
|
+
):
|
|
51
|
+
rows = cursor.rows()
|
|
52
|
+
if not rows:
|
|
53
|
+
return None
|
|
54
|
+
row = rows[0]
|
|
55
|
+
if filter is not None:
|
|
56
|
+
row = filter(row)
|
|
57
|
+
if fetch is not None:
|
|
58
|
+
return inspect_model(fetch).restore(row)
|
|
59
|
+
return row
|