Skip to content

Commit 212ae84

Browse files
authored
Merge pull request #2 from weynelucas/feature/custom_schema_editor
Add backed for custom schema edition
2 parents 6c1a529 + 483cd02 commit 212ae84

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2044
-398
lines changed

.editorconfig

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 4
6+
insert_final_newline = true
7+
trim_trailing_whitespace = true
8+
end_of_line = lf
9+
charset = utf-8
10+
11+
[*.config]
12+
indent_size = 2
13+
14+
# Use 2 spaces for YAML files
15+
[*.yml]
16+
indent_size = 2
17+
18+
# The JSON files contain newlines inconsistently
19+
[*.json]
20+
indent_size = 2
21+
insert_final_newline = ignore
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3+
4+
name: Build
5+
6+
on:
7+
push:
8+
paths:
9+
- '**.py'
10+
- '**.yml'
11+
- '**.cfg'
12+
branches:
13+
- 'develop'
14+
- 'master'
15+
16+
pull_request:
17+
paths:
18+
- '**.py'
19+
- '**.yml'
20+
- '**.cfg'
21+
branches:
22+
- 'develop'
23+
- 'master'
24+
25+
jobs:
26+
build:
27+
28+
runs-on: ubuntu-latest
29+
strategy:
30+
matrix:
31+
python-version: [3.6, 3.7, 3.8, 3.9]
32+
django-version: [1.11, 2.2]
33+
34+
steps:
35+
- name: Checkout repository
36+
uses: actions/checkout@v2
37+
with:
38+
fetch-depth: 2
39+
40+
- name: Set up Python ${{ matrix.python-version }}
41+
uses: actions/setup-python@v2
42+
with:
43+
python-version: ${{ matrix.python-version }}
44+
45+
- name: Install dependencies
46+
run: |
47+
python -m pip install --upgrade pip
48+
pip install Django~=${{ matrix.django-version }}.0
49+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
50+
51+
- name: Lint with flake8
52+
run: flake8 . --count --show-source --statistics
53+
54+
- name: Run tests with pytest
55+
run: pytest --cov
56+
57+
- name: Upload coverage to Codecov
58+
uses: codecov/codecov-action@v1
59+
if: ${{ matrix.python-version == '3.9' && matrix.django-version == '2.2' }}
60+
with:
61+
token: ${{ secrets.CODECOV_TOKEN }}
62+
fail_ci_if_error: false

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,6 @@ ENV/
9999

100100
# mypy
101101
.mypy_cache/
102+
103+
# VS Code
104+
.vscode/

README.md

Lines changed: 20 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,132 +1,33 @@
1-
[![PyPi version](https://img.shields.io/pypi/v/django-db-adapter.svg)](https://pypi.python.org/pypi/django-db-adapter)
1+
# Django DB Adapter
22

3-
# django-db-adapter
4-
A configurable database backend for Oracle
3+
[![Build](https://github.com/weynelucas/django-db-adapter/workflows/Build/badge.svg)](https://github.com/weynelucas/django-db-adapter/actions)
4+
[![codecov](https://codecov.io/gh/weynelucas/django-db-adapter/branch/master/graph/badge.svg?token=EZyTLmsPhm)](https://codecov.io/gh/weynelucas/django-db-adapter)
5+
[![PyPI - Release](https://img.shields.io/pypi/v/django-db-adapter.svg)](https://pypi.python.org/pypi/django-db-adapter)
6+
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-db-adapter)](https://pypi.python.org/pypi/django-db-adapter)
7+
[![PyPI - Django Version](https://img.shields.io/pypi/djversions/django-db-adapters)](https://pypi.python.org/pypi/django-db-adapter)
58

6-
## Requirements
7-
django-db-adapter was tested with the following requirements:
89

9-
- [Python](https://www.python.org/) (3+)
10-
- [Django](https://docs.djangoproject.com/) (1.11)
11-
- [cx_Oracle](http://cx-oracle.readthedocs.io/en/latest/) (5.2+)
10+
A configurable database backend to customize schema creation
1211

13-
The following packages are optional:
14-
- [progressbar2](https://pypi.python.org/pypi/progressbar2) (3.34.0+) - Used only to display progress during `sqlmigrateall` command
12+
# Requirements
13+
- Python (3.6, 3.7, 3.8, 3.9)
14+
- Django (1.11, 2.2)
1515

16-
## Installation
17-
Install using pip, including any optional packages you want...
1816

19-
```
20-
pip install django-db-adapter
21-
```
22-
23-
...or clone the project from github.
24-
25-
```
26-
git clone https://github.com/weynelucas/django-db-adapter.git
27-
```
28-
29-
Add `'db_adapter'` at the top of your `INSTALLED_APPS` setting.
30-
31-
```python
32-
INSTALLED_APPS = (
33-
...,
34-
'db_adapter'
35-
)
36-
```
37-
38-
## Quickstart
39-
Any global settings for a django-db-adapter are kept in a single configuration dictionary named `DB_ADAPTER`
17+
We highly recommend and only officially support the latest patch release of each Python and Django series.
4018

41-
```python
42-
DB_ADAPTER = {
43-
'SCHEMA': 'CONN_ORCL',
44-
'ALLOWED_BACKENDS': ['oracle'],
45-
'PREFIX': {
46-
'TABLE': 'tb_',
47-
'FOREIGN_KEY': 'ce_',
48-
'INDEX': 'ix_',
49-
'UNIQUE': 'ct_',
50-
'TRIGGER': 'tg_',
51-
'SEQUENCE': 'sq_'
52-
}
53-
}
54-
```
55-
56-
You must setting the connection parameter `ENGINE` from `DATABASES` with the custom oracle database backend to apply your `DB_ADAPTER` settings.
57-
58-
```python
59-
DATABASES = {
60-
'default': {
61-
'ENGINE': 'db_adapter.db.backends.oracle',
62-
'NAME': 'mydatabase',
63-
'USER': 'mydatabaseuser',
64-
'PASSWORD': 'mypassword',
65-
'HOST': '127.0.0.1',
66-
'PORT': '1521'
67-
}
68-
}
69-
```
19+
# Installation
20+
Install using `pip`...
7021

71-
## Settings
72-
Configuration for django-db-adapter is all namespaced inside a single Django setting, named `DB_ADAPTER`.
73-
74-
If you need to access the values of `db_adapter` settings in your project, you should use the `settings` object. For example.
75-
76-
```python
77-
from db_adapter.config import settings
78-
79-
print(settings.SCHEMA)
80-
print(settings.PREFIX['TABLE'])
22+
```bash
23+
pip install django-db-adapter
8124
```
8225

83-
### Global settings
84-
85-
#### `SCHEMA`
86-
**Default:** `None`
87-
88-
String with user schema name of you database connection. This value will be appended to all database queries.
89-
90-
#### `ALLOWED_BACKENDS`
91-
**Default:** `[ '*' ]`
92-
93-
List of database backends names allowed to perform non-oracle actions. Add table prefixes and the command `sqlmigrateall` are actions that not require a oracle backend. If a backend are not present on list, theese action will not be performed.
26+
Add `'db_adapter'` to your `INSTALLED_APPS` setting.
9427

95-
Options are: `'mysql'`, `'oracle'`, `'postgresql'`, `'postgresql_psycopg2'`, `'sqlite'` or `*` for allow all backends to perform non-oracle actions
96-
97-
98-
#### `PREFIX`
99-
**Default:**
10028
```python
101-
{
102-
'TABLE': 'tb_',
103-
'FOREIGN_KEY': 'fk_',
104-
'INDEX': 'ix_',
105-
'UNIQUE': 'uniq_',
106-
'TRIGGER': 'tg_',
107-
'SEQUENCE': 'sq_'
108-
}
109-
```
110-
111-
Default prefix mapping for all database objects. This configuration allow backend to create DDL commands applying theese prefixes for each database object.
112-
113-
```sql
114-
CREATE TABLE "TB_PERSON" ("ID" NUMBER(11) NOT NULL PRIMARY KEY, "NAME" NVARCHAR2(255) NULL);
115-
116-
DECLARE
117-
i INTEGER;
118-
BEGIN
119-
SELECT COUNT(1) INTO i FROM USER_SEQUENCES
120-
WHERE SEQUENCE_NAME = 'SQ_PERSON';
121-
IF i = 0 THEN
122-
EXECUTE IMMEDIATE 'CREATE SEQUENCE "SQ_PERSON"';
123-
END IF;
124-
END;
125-
/;
29+
INSTALLED_APPS = [
30+
...
31+
'db_adapter',
32+
]
12633
```
127-
128-
## Release Notes
129-
130-
- 1.0.0 - 16/04/2018 - First release
131-
- 1.0.1 - 16/04/2018 - Rename package and fix setup issues
132-
- 1.0.2 - 17/04/2018 - Fix documentation preview

db_adapter/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
default_app_config = 'db_adapter.apps.DatabaseAdapterConfig'

db_adapter/apps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from django.apps import AppConfig
22

33

4-
class DbEditorConfig(AppConfig):
5-
name = 'db_adapter'
4+
class DatabaseAdapterConfig(AppConfig):
5+
name = 'db_adapter'

db_adapter/config/settings.py

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
from functools import lru_cache
2+
3+
from django.db.utils import ProgrammingError
4+
from django.utils.functional import cached_property
5+
6+
from db_adapter.name_builders import ObjectNameBuilder
7+
from db_adapter.utils import enforce_model, enforce_model_fields
8+
9+
10+
class DatabaseOperations:
11+
sql_create_sequence = None
12+
sql_create_trigger = None
13+
14+
name_builder_class = ObjectNameBuilder
15+
16+
def autoinc_sql(self, table, column):
17+
if not self.sql_create_sequence and not self.sql_create_trigger:
18+
return None
19+
20+
model, field = self._enforce_model_field_instances(table, column)
21+
22+
args = {
23+
'sq_name': self._get_sequence_name(model, field),
24+
'tr_name': self._get_trigger_name(model, field),
25+
'tbl_name': self.quote_name(table),
26+
'col_name': self.quote_name(column),
27+
}
28+
29+
try:
30+
_, max_value = self.integer_field_range(field.get_internal_type())
31+
args.update(sq_max_value=max_value)
32+
except KeyError:
33+
pass
34+
35+
try:
36+
sequence_sql = self.sql_create_sequence % args
37+
trigger_sql = self.sql_create_trigger % args
38+
return sequence_sql, trigger_sql
39+
except KeyError as err:
40+
if 'sq_max_value' in err.args:
41+
raise ProgrammingError(
42+
'Cannot retrieve the range of the column type bound to the '
43+
'field %s' % field.name
44+
)
45+
46+
@cached_property
47+
def name_builder(self):
48+
return self.name_builder_class()
49+
50+
@lru_cache(maxsize=None)
51+
def _enforce_model_field_instances(self, table, column=''):
52+
model = enforce_model(table)
53+
(field,) = enforce_model_fields(model, [column])
54+
55+
return model, field
56+
57+
def _get_sequence_name(self, table, column):
58+
model, field = self._enforce_model_field_instances(table, column)
59+
name = self.name_builder.process_name(model, [field], type='sequence')
60+
return self.quote_name(name)
61+
62+
def _get_trigger_name(self, table, column=''):
63+
model, field = self._enforce_model_field_instances(table, column)
64+
name = self.name_builder.process_name(model, [field], type='trigger')
65+
return self.quote_name(name)

0 commit comments

Comments
 (0)