Skip to content

Commit

Permalink
Convert Relation types to hologram.JsonSchemaMixin
Browse files Browse the repository at this point in the history
Fix a lot of mypy things, add a number of adapter-ish modules to it
Split relations and columns into separate files
split context.common into base + common
 - base is all that's required for the config renderer
Move Credentials into connection contracts since that's what they really are
Removed model_name/table_name -> consolidated to identifier
 - I hope I did not break seeds, which claimed to care about render(False)
Unify shared 'external' relation type with bigquery's own
hack workarounds for some import cycles with plugin registration and config p
arsing
Assorted backwards compatibility fixes around types, deep_merge vs shallow merge
Remove APIObject
  • Loading branch information
Jacob Beck committed Sep 26, 2019
1 parent 23484b1 commit 3e95e43
Show file tree
Hide file tree
Showing 40 changed files with 1,012 additions and 1,054 deletions.
8 changes: 5 additions & 3 deletions core/dbt/adapters/base/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# these are all just exports, #noqa them so flake8 will be happy

# TODO: Should we still include this in the `adapters` namespace?
from dbt.contracts.connection import Credentials # noqa
from dbt.adapters.base.meta import available # noqa
from dbt.adapters.base.relation import BaseRelation # noqa
from dbt.adapters.base.relation import Column # noqa
from dbt.adapters.base.connections import BaseConnectionManager # noqa
from dbt.adapters.base.connections import Credentials # noqa
from dbt.adapters.base.relation import BaseRelation, RelationType # noqa
from dbt.adapters.base.column import Column # noqa
from dbt.adapters.base.impl import BaseAdapter # noqa
from dbt.adapters.base.plugin import AdapterPlugin # noqa
93 changes: 93 additions & 0 deletions core/dbt/adapters/base/column.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from dataclasses import dataclass

from hologram import JsonSchemaMixin

from typing import TypeVar, Dict, ClassVar, Any, Optional, Type

Self = TypeVar('Self', bound='Column')


@dataclass
class Column(JsonSchemaMixin):
TYPE_LABELS: ClassVar[Dict[str, str]] = {
'STRING': 'TEXT',
'TIMESTAMP': 'TIMESTAMP',
'FLOAT': 'FLOAT',
'INTEGER': 'INT'
}
column: str
dtype: str
char_size: Optional[int] = None
numeric_precision: Optional[Any] = None
numeric_scale: Optional[Any] = None

@classmethod
def translate_type(cls, dtype: str) -> str:
return cls.TYPE_LABELS.get(dtype.upper(), dtype)

@classmethod
def create(cls: Type[Self], name, label_or_dtype: str) -> Self:
column_type = cls.translate_type(label_or_dtype)
return cls(name, column_type)

@property
def name(self) -> str:
return self.column

@property
def quoted(self) -> str:
return '"{}"'.format(self.column)

@property
def data_type(self) -> str:
if self.is_string():
return Column.string_type(self.string_size())
elif self.is_numeric():
return Column.numeric_type(self.dtype, self.numeric_precision,
self.numeric_scale)
else:
return self.dtype

def is_string(self) -> bool:
return self.dtype.lower() in ['text', 'character varying', 'character',
'varchar']

def is_numeric(self) -> bool:
return self.dtype.lower() in ['numeric', 'number']

def string_size(self) -> int:
if not self.is_string():
raise RuntimeError("Called string_size() on non-string field!")

if self.dtype == 'text' or self.char_size is None:
# char_size should never be None. Handle it reasonably just in case
return 256
else:
return int(self.char_size)

def can_expand_to(self: Self, other_column: Self) -> bool:
"""returns True if this column can be expanded to the size of the
other column"""
if not self.is_string() or not other_column.is_string():
return False

return other_column.string_size() > self.string_size()

def literal(self, value: Any) -> str:
return "{}::{}".format(value, self.data_type)

@classmethod
def string_type(cls, size: int) -> str:
return "character varying({})".format(size)

@classmethod
def numeric_type(cls, dtype: str, precision: Any, scale: Any) -> str:
# This could be decimal(...), numeric(...), number(...)
# Just use whatever was fed in here -- don't try to get too clever
if precision is None or scale is None:
return dtype
else:
return "{}({},{})".format(dtype, precision, scale)

def __repr__(self) -> str:
return "<Column {} ({})>".format(self.name, self.data_type)
Loading

0 comments on commit 3e95e43

Please sign in to comment.