Skip to content

Commit 6640991

Browse files
committed
data repository added
1 parent a74ef58 commit 6640991

15 files changed

+437
-1
lines changed

metering/__init__.py

Whitespace-only changes.

metering/alembic.ini

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# A generic, single database configuration.
2+
3+
[alembic]
4+
# path to migration scripts
5+
script_location = alembic
6+
7+
# template used to generate migration files
8+
# file_template = %%(rev)s_%%(slug)s
9+
10+
# timezone to use when rendering the date
11+
# within the migration file as well as the filename.
12+
# string value is passed to dateutil.tz.gettz()
13+
# leave blank for localtime
14+
# timezone =
15+
16+
# max length of characters to apply to the
17+
# "slug" field
18+
# truncate_slug_length = 40
19+
20+
# set to 'true' to run the environment during
21+
# the 'revision' command, regardless of autogenerate
22+
# revision_environment = false
23+
24+
# set to 'true' to allow .pyc and .pyo files without
25+
# a source .py file to be detected as revisions in the
26+
# versions/ directory
27+
# sourceless = false
28+
29+
# version location specification; this defaults
30+
# to alembic/versions. When using multiple version
31+
# directories, initial revisions must be specified with --version-path
32+
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
33+
34+
# the output encoding used when revision files
35+
# are written from script.py.mako
36+
# output_encoding = utf-8
37+
38+
sqlalchemy.url = "db_url"
39+
40+
41+
# Logging configuration
42+
[loggers]
43+
keys = root,sqlalchemy,alembic
44+
45+
[handlers]
46+
keys = console
47+
48+
[formatters]
49+
keys = generic
50+
51+
[logger_root]
52+
level = WARN
53+
handlers = console
54+
qualname =
55+
56+
[logger_sqlalchemy]
57+
level = WARN
58+
handlers =
59+
qualname = sqlalchemy.engine
60+
61+
[logger_alembic]
62+
level = INFO
63+
handlers =
64+
qualname = alembic
65+
66+
[handler_console]
67+
class = StreamHandler
68+
args = (sys.stderr,)
69+
level = NOTSET
70+
formatter = generic
71+
72+
[formatter_generic]
73+
format = %(levelname)-5.5s [%(name)s] %(message)s
74+
datefmt = %H:%M:%S

metering/alembic/README

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Generic single-database configuration.

metering/alembic/env.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
from logging.config import fileConfig
3+
4+
from sqlalchemy import engine_from_config
5+
from sqlalchemy import pool
6+
7+
from alembic import context
8+
9+
# this is the Alembic Config object, which provides
10+
# access to the values within the .ini file in use.
11+
from metering.models import Base
12+
13+
config = context.config
14+
15+
# Interpret the config file for Python logging.
16+
# This line sets up loggers basically.
17+
fileConfig(config.config_file_name)
18+
19+
# add your model's MetaData object here
20+
# for 'autogenerate' support
21+
# from myapp import mymodel
22+
# target_metadata = mymodel.Base.metadata
23+
target_metadata = Base.metadata
24+
25+
# other values from the config, defined by the needs of env.py,
26+
# can be acquired:
27+
# my_important_option = config.get_main_option("my_important_option")
28+
# ... etc.
29+
30+
31+
def run_migrations_offline():
32+
"""Run migrations in 'offline' mode.
33+
34+
This configures the context with just a URL
35+
and not an Engine, though an Engine is acceptable
36+
here as well. By skipping the Engine creation
37+
we don't even need a DBAPI to be available.
38+
39+
Calls to context.execute() here emit the given string to the
40+
script output.
41+
42+
"""
43+
url = config.get_main_option("sqlalchemy.url")
44+
context.configure(
45+
url=url, target_metadata=target_metadata, literal_binds=True
46+
)
47+
48+
with context.begin_transaction():
49+
context.run_migrations()
50+
51+
52+
def run_migrations_online():
53+
"""Run migrations in 'online' mode.
54+
55+
In this scenario we need to create an Engine
56+
and associate a connection with the context.
57+
58+
"""
59+
connectable = engine_from_config(
60+
config.get_section(config.config_ini_section),
61+
prefix="sqlalchemy.",
62+
poolclass=pool.NullPool,
63+
)
64+
65+
with connectable.connect() as connection:
66+
context.configure(
67+
connection=connection, target_metadata=target_metadata
68+
)
69+
70+
with context.begin_transaction():
71+
context.run_migrations()
72+
73+
74+
if context.is_offline_mode():
75+
run_migrations_offline()
76+
else:
77+
run_migrations_online()

metering/alembic/script.py.mako

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""${message}
2+
3+
Revision ID: ${up_revision}
4+
Revises: ${down_revision | comma,n}
5+
Create Date: ${create_date}
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
${imports if imports else ""}
11+
12+
# revision identifiers, used by Alembic.
13+
revision = ${repr(up_revision)}
14+
down_revision = ${repr(down_revision)}
15+
branch_labels = ${repr(branch_labels)}
16+
depends_on = ${repr(depends_on)}
17+
18+
19+
def upgrade():
20+
${upgrades if upgrades else "pass"}
21+
22+
23+
def downgrade():
24+
${downgrades if downgrades else "pass"}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""added tables
2+
3+
Revision ID: 699f08a8834e
4+
Revises:
5+
Create Date: 2019-08-07 22:55:12.604492
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '699f08a8834e'
14+
down_revision = None
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table('service_config',
22+
sa.Column('id', sa.Integer(), nullable=False),
23+
sa.Column('row_id', sa.VARCHAR(length=32), nullable=False),
24+
sa.Column('service_id', sa.VARCHAR(length=32), nullable=False),
25+
sa.Column('free_calls', sa.Integer(), nullable=False),
26+
sa.Column('effective_start_date', sa.TIMESTAMP(timezone=True), nullable=True),
27+
sa.Column('effective_end_date', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
28+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), nullable=True),
29+
sa.PrimaryKeyConstraint('id')
30+
)
31+
op.create_table('user_org_group',
32+
sa.Column('id', sa.Integer(), nullable=False),
33+
sa.Column('group', sa.VARCHAR(length=32), nullable=True),
34+
sa.Column('org_name', sa.VARCHAR(length=32), nullable=False),
35+
sa.Column('user_name', sa.VARCHAR(length=32), nullable=False),
36+
sa.Column('user_id', sa.Integer(), nullable=False),
37+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
38+
sa.Column('service_id', sa.VARCHAR(length=32), nullable=False),
39+
sa.Column('resource', sa.VARCHAR(length=32), nullable=True),
40+
sa.PrimaryKeyConstraint('id')
41+
)
42+
op.create_table('usage_table',
43+
sa.Column('id', sa.Integer(), nullable=False),
44+
sa.Column('user_org_group_id', sa.Integer(), nullable=False),
45+
sa.Column('usage_type', sa.VARCHAR(length=32), nullable=False),
46+
sa.Column('usage_value', sa.Integer(), nullable=False),
47+
sa.Column('start_time', sa.TIMESTAMP(timezone=True), nullable=True),
48+
sa.Column('end_time', sa.TIMESTAMP(timezone=True), nullable=True),
49+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
50+
sa.ForeignKeyConstraint(['user_org_group_id'], ['user_org_group.id'], ),
51+
sa.PrimaryKeyConstraint('id')
52+
)
53+
# ### end Alembic commands ###
54+
55+
56+
def downgrade():
57+
# ### commands auto generated by Alembic - please adjust! ###
58+
op.drop_table('usage_table')
59+
op.drop_table('user_org_group')
60+
op.drop_table('service_config')
61+
# ### end Alembic commands ###

metering/models.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,40 @@
1+
from sqlalchemy import Column, Integer, VARCHAR, ForeignKey, TIMESTAMP, func
12

3+
from sqlalchemy.ext.declarative import declarative_base
4+
from sqlalchemy.orm import relationship
25

6+
Base = declarative_base()
7+
8+
9+
class OrgServiceConfigModel(Base):
10+
__tablename__ = 'service_config'
11+
id = Column('id', Integer, primary_key=True)
12+
org_id = Column('row_id', VARCHAR(32), nullable=False)
13+
service_id = Column('service_id', VARCHAR(32), nullable=False)
14+
free_calls = Column('free_calls', Integer, nullable=False)
15+
effective_start_date = Column('effective_start_date', TIMESTAMP(timezone=True))
16+
effective_end_date = Column('effective_end_date', TIMESTAMP(timezone=True), server_default=func.current_timestamp())
17+
created_at = Column('created_at', TIMESTAMP(timezone=True))
18+
19+
20+
class UserOrgGroupModel(Base):
21+
__tablename__ = 'user_org_group'
22+
id = Column('id', Integer, primary_key=True)
23+
payment_group_id = Column('group', VARCHAR(32))
24+
org_id = Column('org_name', VARCHAR(32), nullable=False)
25+
user_name = Column('user_name', VARCHAR(32), nullable=False)
26+
user_id = Column('user_id', Integer, nullable=False)
27+
created_at = Column('created_at', TIMESTAMP(timezone=True), nullable=False, server_default=func.current_timestamp())
28+
service_id = Column('service_id', VARCHAR(32), nullable=False)
29+
resource = Column('resource', VARCHAR(32))
30+
31+
32+
class UsageModel(Base):
33+
__tablename__ = 'usage_table'
34+
id = Column('id', Integer, primary_key=True)
35+
user_org_group_id = Column('user_org_group_id', Integer, ForeignKey('user_org_group.id'), nullable=False)
36+
usage_type = Column('usage_type', VARCHAR(32), nullable=False)
37+
usage_value = Column('usage_value', Integer, nullable=False)
38+
start_time = Column('start_time', TIMESTAMP(timezone=True))
39+
end_time = Column('end_time', TIMESTAMP(timezone=True))
40+
created_at = Column('created_at', TIMESTAMP(timezone=True), nullable=False, server_default=func.current_timestamp())

metering/repository/__init__.py

Whitespace-only changes.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
3+
from sqlalchemy import create_engine
4+
from sqlalchemy.orm import sessionmaker
5+
from settings import DB_URL
6+
7+
engine = create_engine(DB_URL, echo=True)
8+
9+
Session = sessionmaker(bind=engine)
10+
default_session = Session()
11+
12+
13+
class BaseRepository(object):
14+
15+
def get_default_session(self, session=None):
16+
if not session:
17+
return default_session
18+
19+
return session
20+
21+
def add_item(self, item, session=None):
22+
session = self.get_default_session(session)
23+
session.add(item)
24+
return item
25+
26+
def remove_item(self, item, session=None):
27+
pass
28+
29+
def update_item(self, item, session=None):
30+
pass
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from models import OrgServiceConfigModel
2+
from repository.base_repository import BaseRepository
3+
4+
5+
class OrgServiceRepo(BaseRepository):
6+
7+
def get_service_config(self, org_id, service_id, optin_time):
8+
session = self.get_default_session()
9+
if optin_time is not None:
10+
service_config = session.query(OrgServiceConfigModel.free_calls.label('free_calls')) \
11+
.filter(OrgServiceConfigModel.org_id == org_id) \
12+
.filter(OrgServiceConfigModel.service_id == service_id) \
13+
.filter(OrgServiceConfigModel.effective_start_date <= optin_time) \
14+
.filter(OrgServiceConfigModel.effective_end_date >= optin_time).first()
15+
else:
16+
service_config = session.query(OrgServiceConfigModel.free_calls.label('free_calls')) \
17+
.filter(OrgServiceConfigModel.org_id == org_id) \
18+
.filter(OrgServiceConfigModel.service_id == service_id)\
19+
.order_by(OrgServiceConfigModel.created_at.desc()).first()
20+
return service_config

0 commit comments

Comments
 (0)