Switched SQL backend to MySQL
parent
c821491cd4
commit
4c0d8d2384
|
@ -0,0 +1,34 @@
|
||||||
|
import configparser
|
||||||
|
|
||||||
|
def read_config():
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read('GeoffreyConfig.ini')
|
||||||
|
|
||||||
|
if len(config.sections()) == 0:
|
||||||
|
create_config(config)
|
||||||
|
print("GeoffreyConfig.ini generated.")
|
||||||
|
quit(0)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def create_config(config):
|
||||||
|
config['Discord'] = {'Token': ''}
|
||||||
|
config['SQL'] = {'Dialect+Driver': '', 'username': '', 'password':'', 'host': '', 'port': '', 'database':'',
|
||||||
|
'test_args':''}
|
||||||
|
|
||||||
|
with open('GeoffreyConfig.ini', 'w') as configfile:
|
||||||
|
config.write(configfile)
|
||||||
|
|
||||||
|
|
||||||
|
def get_engine_arg(config):
|
||||||
|
driver = config['SQL']['Dialect+Driver']
|
||||||
|
username = config['SQL']['username']
|
||||||
|
password = config['SQL']['password']
|
||||||
|
host = config['SQL']['host']
|
||||||
|
port = config['SQL']['port']
|
||||||
|
database_name = config['SQL']['database']
|
||||||
|
|
||||||
|
engine_args = '{}://{}:{}@{}:{}/{}'
|
||||||
|
|
||||||
|
return engine_args.format(driver, username, password, host, port, database_name)
|
|
@ -24,4 +24,8 @@ class PlayerNotFound(DataBaseError):
|
||||||
class EntryNameNotUniqueError(DataBaseError):
|
class EntryNameNotUniqueError(DataBaseError):
|
||||||
'''A location by that name is already in the database.'''
|
'''A location by that name is already in the database.'''
|
||||||
|
|
||||||
|
class StringTooLong(DataBaseError):
|
||||||
|
'''Given string is too long.'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
from sqlalchemy import Column, Integer, String, ForeignKey, Enum
|
from sqlalchemy import Column, Integer, String, ForeignKey, Enum, create_engine, exists, MetaData
|
||||||
import enum
|
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
|
||||||
from BotErrors import *
|
|
||||||
from sqlalchemy import create_engine, exists, literal
|
|
||||||
from sqlalchemy.orm import sessionmaker, relationship, column_property
|
from sqlalchemy.orm import sessionmaker, relationship, column_property
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError, DataError
|
||||||
import sqlalchemy
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from MinecraftAccountInfoGrabber import *
|
from sqlalchemy.sql import expression
|
||||||
from difflib import SequenceMatcher
|
from difflib import SequenceMatcher
|
||||||
|
import enum
|
||||||
|
from BotErrors import *
|
||||||
|
from MinecraftAccountInfoGrabber import *
|
||||||
|
|
||||||
SQL_Base = declarative_base()
|
SQL_Base = declarative_base()
|
||||||
|
|
||||||
|
@ -184,7 +183,7 @@ class DatabaseInterface:
|
||||||
|
|
||||||
def delete_location(self, owner, name):
|
def delete_location(self, owner, name):
|
||||||
expr = (Location.owner == owner) & (Location.name == name)
|
expr = (Location.owner == owner) & (Location.name == name)
|
||||||
self.database.delete_entry(Shop, expr)
|
self.database.delete_entry(Location, expr)
|
||||||
|
|
||||||
|
|
||||||
class DiscordDatabaseInterface(DatabaseInterface):
|
class DiscordDatabaseInterface(DatabaseInterface):
|
||||||
|
@ -243,6 +242,7 @@ class GeoffreyDatabase:
|
||||||
self.engine = create_engine(engine_arg, echo=True)
|
self.engine = create_engine(engine_arg, echo=True)
|
||||||
Session = sessionmaker(bind=self.engine)
|
Session = sessionmaker(bind=self.engine)
|
||||||
self.session = Session()
|
self.session = Session()
|
||||||
|
self.meta = MetaData()
|
||||||
SQL_Base.metadata.create_all(self.engine)
|
SQL_Base.metadata.create_all(self.engine)
|
||||||
|
|
||||||
def add_object(self, obj):
|
def add_object(self, obj):
|
||||||
|
@ -252,7 +252,12 @@ class GeoffreyDatabase:
|
||||||
self.session.add(obj)
|
self.session.add(obj)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
|
self.session.rollback()
|
||||||
raise EntryNameNotUniqueError
|
raise EntryNameNotUniqueError
|
||||||
|
except DataError:
|
||||||
|
self.session.rollback()
|
||||||
|
raise StringTooLong
|
||||||
|
|
||||||
|
|
||||||
def query_by_filter(self, obj_type, * args):
|
def query_by_filter(self, obj_type, * args):
|
||||||
filter_value = self.combine_filter(args)
|
filter_value = self.combine_filter(args)
|
||||||
|
@ -264,6 +269,7 @@ class GeoffreyDatabase:
|
||||||
|
|
||||||
if entry.first() is not None:
|
if entry.first() is not None:
|
||||||
entry.delete()
|
entry.delete()
|
||||||
|
self.session.commit()
|
||||||
else:
|
else:
|
||||||
raise DeleteEntryError
|
raise DeleteEntryError
|
||||||
|
|
||||||
|
@ -277,7 +283,7 @@ class GeoffreyDatabase:
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def combine_filter(self, filter_value):
|
def combine_filter(self, filter_value):
|
||||||
return sqlalchemy.sql.expression.and_(filter_value[0])
|
return expression.and_(filter_value[0])
|
||||||
|
|
||||||
|
|
||||||
class TunnelDirection(enum.Enum):
|
class TunnelDirection(enum.Enum):
|
||||||
|
@ -321,11 +327,12 @@ class Dimension(enum.Enum):
|
||||||
class Player(SQL_Base):
|
class Player(SQL_Base):
|
||||||
__tablename__ = 'Players'
|
__tablename__ = 'Players'
|
||||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
mc_uuid = Column(String)
|
mc_uuid = Column(String(128))
|
||||||
discord_uuid = Column(String)
|
discord_uuid = Column(String(128))
|
||||||
name = Column(String)
|
name = Column(String(128))
|
||||||
locations = relationship("Location", back_populates="owner", lazy='dynamic',
|
locations = relationship("Location", back_populates="owner", lazy='dynamic',
|
||||||
cascade="save-update, merge, delete, delete-orphan")
|
cascade="save-update, merge, delete, delete-orphan")
|
||||||
|
|
||||||
tunnels = relationship("Tunnel", back_populates="owner", lazy='dynamic',
|
tunnels = relationship("Tunnel", back_populates="owner", lazy='dynamic',
|
||||||
cascade="save-update, merge, delete, delete-orphan")
|
cascade="save-update, merge, delete, delete-orphan")
|
||||||
|
|
||||||
|
@ -342,8 +349,8 @@ class Tunnel(SQL_Base):
|
||||||
tunnel_direction = Column(Enum(TunnelDirection))
|
tunnel_direction = Column(Enum(TunnelDirection))
|
||||||
owner_id = Column(Integer, ForeignKey('Players.id'))
|
owner_id = Column(Integer, ForeignKey('Players.id'))
|
||||||
owner = relationship("Player", back_populates="tunnels", cascade="save-update, merge, delete")
|
owner = relationship("Player", back_populates="tunnels", cascade="save-update, merge, delete")
|
||||||
location_id = Column(Integer, ForeignKey('Locations.id'))
|
location_id = Column(Integer, ForeignKey('Locations.id', ondelete='CASCADE'))
|
||||||
location = relationship("Location", back_populates="tunnel", cascade="save-update, merge, delete")
|
location = relationship("Location", back_populates="tunnel")
|
||||||
|
|
||||||
def __init__(self, owner, tunnel_color, tunnel_number, location=None):
|
def __init__(self, owner, tunnel_color, tunnel_number, location=None):
|
||||||
try:
|
try:
|
||||||
|
@ -362,18 +369,16 @@ class Location(SQL_Base):
|
||||||
__tablename__ = 'Locations'
|
__tablename__ = 'Locations'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
name = Column(String, unique=True)
|
name = Column(String(128), unique=True, )
|
||||||
x = Column(Integer)
|
x = Column(Integer)
|
||||||
y = Column(Integer)
|
|
||||||
z = Column(Integer)
|
z = Column(Integer)
|
||||||
|
|
||||||
tunnel = relationship("Tunnel", back_populates="location", uselist=False,
|
tunnel = relationship("Tunnel", uselist=False, cascade="all, delete-orphan")
|
||||||
cascade="save-update, merge, delete, delete-orphan")
|
|
||||||
dimension = Column(Enum(Dimension))
|
dimension = Column(Enum(Dimension))
|
||||||
|
|
||||||
owner_id = Column(Integer, ForeignKey('Players.id'))
|
owner_id = Column(Integer, ForeignKey('Players.id', ondelete='CASCADE'))
|
||||||
owner = relationship("Player", back_populates="locations", cascade="save-update, merge, delete")
|
owner = relationship("Player", back_populates="locations", cascade="all, delete-orphan", single_parent=True)
|
||||||
type = Column(String)
|
type = Column(String(128))
|
||||||
|
|
||||||
__mapper_args__ = {
|
__mapper_args__ = {
|
||||||
'polymorphic_on': type,
|
'polymorphic_on': type,
|
||||||
|
@ -413,15 +418,13 @@ class Location(SQL_Base):
|
||||||
|
|
||||||
class Shop(Location):
|
class Shop(Location):
|
||||||
__tablename__ = 'Shops'
|
__tablename__ = 'Shops'
|
||||||
shop_id = Column(Integer, ForeignKey('Locations.id'), primary_key=True)
|
shop_id = Column(Integer, ForeignKey('Locations.id', ondelete='CASCADE'), primary_key=True)
|
||||||
name = column_property(Column(String), Location.name)
|
name = column_property(Column(String(128)), Location.name)
|
||||||
inventory = relationship('ItemListing', back_populates='shop', cascade='all, delete-orphan')
|
inventory = relationship('ItemListing', back_populates='shop', cascade='all, delete-orphan')
|
||||||
__mapper_args__ = {
|
__mapper_args__ = {
|
||||||
'polymorphic_identity': 'Shop',
|
'polymorphic_identity': 'Shop',
|
||||||
}
|
}
|
||||||
|
|
||||||
column_property()
|
|
||||||
|
|
||||||
def inv_to_str(self):
|
def inv_to_str(self):
|
||||||
|
|
||||||
if len(self.inventory.all()) != 0:
|
if len(self.inventory.all()) != 0:
|
||||||
|
@ -449,12 +452,12 @@ class ItemListing(SQL_Base):
|
||||||
__tablename__ = 'Items'
|
__tablename__ = 'Items'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
name = Column(String)
|
name = Column(String(128))
|
||||||
price = Column(Integer)
|
price = Column(Integer)
|
||||||
amount = Column(Integer)
|
amount = Column(Integer)
|
||||||
|
|
||||||
shop_id = Column(Integer, ForeignKey('Shops.shop_id'))
|
shop_id = Column(Integer, ForeignKey('Shops.shop_id', ondelete='CASCADE'))
|
||||||
shop = relationship("Shop", back_populates="inventory")
|
shop = relationship("Shop", back_populates="inventory", single_parent=True)
|
||||||
|
|
||||||
def __init__(self, name, price, amount, shop):
|
def __init__(self, name, price, amount, shop):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
36
Geoffrey.py
36
Geoffrey.py
|
@ -3,7 +3,8 @@ from DatabaseModels import *
|
||||||
from BotErrors import *
|
from BotErrors import *
|
||||||
from MinecraftAccountInfoGrabber import *
|
from MinecraftAccountInfoGrabber import *
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
import configparser
|
from BotConfig import *
|
||||||
|
|
||||||
import shlex
|
import shlex
|
||||||
#from WebInterface import *
|
#from WebInterface import *
|
||||||
|
|
||||||
|
@ -313,46 +314,15 @@ def get_args_dict(args):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def create_config():
|
|
||||||
config['Discord'] = {'Token': ''}
|
|
||||||
config['SQL'] = {'Dialect+Driver': 'Test', 'username': '', 'password':'', 'host': '', 'port': '', 'database':''}
|
|
||||||
|
|
||||||
with open('GeoffreyConfig.ini', 'w') as configfile:
|
|
||||||
config.write(configfile)
|
|
||||||
|
|
||||||
def get_engine_arg(config):
|
|
||||||
driver = config['SQL']['Dialect+Driver']
|
|
||||||
username = config['SQL']['username']
|
|
||||||
password = config['SQL']['password']
|
|
||||||
host = config['SQL']['host']
|
|
||||||
port = config['SQL']['port']
|
|
||||||
database_name = config['SQL']['database']
|
|
||||||
|
|
||||||
engine_args = '{}://{}:{}@{}:{}/{}'
|
|
||||||
|
|
||||||
return engine_args.format(driver, username, password, host, port, database_name)
|
|
||||||
|
|
||||||
|
|
||||||
# Bot Startup ******************************************************************
|
# Bot Startup ******************************************************************
|
||||||
|
|
||||||
|
config = read_config()
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
config.read('GeoffreyConfig.ini')
|
|
||||||
|
|
||||||
if len(config.sections()) == 0:
|
|
||||||
create_config()
|
|
||||||
print("GeoffreyConfig.ini generated.")
|
|
||||||
quit(0)
|
|
||||||
else:
|
|
||||||
TOKEN = config['Discord']['Token']
|
TOKEN = config['Discord']['Token']
|
||||||
|
|
||||||
if config['SQL']['dialect+driver'] == 'Test':
|
|
||||||
engine_arg = 'sqlite:///temp.db'
|
|
||||||
else:
|
|
||||||
engine_arg = get_engine_arg(config)
|
engine_arg = get_engine_arg(config)
|
||||||
|
|
||||||
database_interface = DiscordDatabaseInterface(engine_arg)
|
database_interface = DiscordDatabaseInterface(engine_arg)
|
||||||
#WebInterface('127.0.0.1', 8081, database)
|
|
||||||
|
|
||||||
bot.run(TOKEN)
|
bot.run(TOKEN)
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,28 @@ from unittest import TestCase
|
||||||
from DatabaseModels import *
|
from DatabaseModels import *
|
||||||
from BotErrors import *
|
from BotErrors import *
|
||||||
from MinecraftAccountInfoGrabber import *
|
from MinecraftAccountInfoGrabber import *
|
||||||
|
from BotConfig import *
|
||||||
|
|
||||||
class TestGeoffreyDatabase(TestCase):
|
class TestGeoffreyDatabase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.interface = DiscordDatabaseInterface('sqlite:///:memory:')
|
config = read_config()
|
||||||
|
|
||||||
|
engine_arg = config['SQL']['test_args']
|
||||||
|
|
||||||
|
self.interface = DiscordDatabaseInterface(engine_arg)
|
||||||
self.owner = Player('ZeroHD', '143072699567177728')
|
self.owner = Player('ZeroHD', '143072699567177728')
|
||||||
self.loc = Location('test', 1, 3, self.owner, dimension='Nether')
|
self.loc = Location('test', 1, 3, self.owner, dimension='Nether')
|
||||||
self.tunnel = Tunnel(self.owner, 'Green', 105, self.loc)
|
self.tunnel = Tunnel(self.owner, 'Green', 105, self.loc)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.interface.database.session.query(Tunnel).delete()
|
||||||
|
self.interface.database.session.query(ItemListing).delete()
|
||||||
|
self.interface.database.session.query(Shop).delete()
|
||||||
|
self.interface.database.session.query(Location).delete()
|
||||||
|
self.interface.database.session.query(Player).delete()
|
||||||
|
|
||||||
|
self.interface.database.session.commit()
|
||||||
|
|
||||||
def test_add_object(self):
|
def test_add_object(self):
|
||||||
self.interface.database.add_object(self.loc)
|
self.interface.database.add_object(self.loc)
|
||||||
self.interface.database.add_object(self.owner)
|
self.interface.database.add_object(self.owner)
|
||||||
|
@ -184,12 +198,11 @@ class TestGeoffreyDatabase(TestCase):
|
||||||
|
|
||||||
def test_big_input(self):
|
def test_big_input(self):
|
||||||
owner = self.add_player()
|
owner = self.add_player()
|
||||||
loc = self.interface.add_location('143072699567177728',
|
|
||||||
'TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', 0, 0, 0)
|
|
||||||
|
|
||||||
loc_list = self.interface.find_location_by_owner(owner)
|
self.assertRaises(StringTooLong, self.interface.add_location, '143072699567177728',
|
||||||
|
'TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT'
|
||||||
self.assertEqual(loc_list[0].id, loc.id)
|
'TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT'
|
||||||
|
'TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', 0, 0,)
|
||||||
|
|
||||||
def test_duplicate_name(self):
|
def test_duplicate_name(self):
|
||||||
self.add_player()
|
self.add_player()
|
||||||
|
@ -207,7 +220,7 @@ class TestGeoffreyDatabase(TestCase):
|
||||||
self.interface.delete_location('143072699567177728', 'test')
|
self.interface.delete_location('143072699567177728', 'test')
|
||||||
|
|
||||||
shops = self.interface.find_shop_selling_item('dirt')
|
shops = self.interface.find_shop_selling_item('dirt')
|
||||||
self.assertGreater(len(shops), 0)
|
self.assertEqual(len(shops), 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue