import logging from ttfrog.db.manager import db from ttfrog.db import schema from sqlalchemy.exc import IntegrityError # move this to json or whatever data = { 'CharacterClass': [ { 'id': 1, 'name': 'fighter', 'hit_dice': '1d10', 'hit_dice_stat': 'CON', 'proficiencies': 'all armor, all shields, simple weapons, martial weapons', 'saving_throws': ['STR, CON'], 'skills': ['Acrobatics', 'Animal Handling', 'Athletics', 'History', 'Insight', 'Intimidation', 'Perception', 'Survival'], }, { 'id': 2, 'name': 'rogue', 'hit_dice': '1d8', 'hit_dice_stat': 'DEX', 'proficiencies': 'simple weapons, hand crossbows, longswords, rapiers, shortswords', 'saving_throws': ['DEX', 'INT'], 'skills': ['Acrobatics', 'Athletics', 'Deception', 'Insight', 'Intimidation', 'Investigation', 'Perception', 'Performance', 'Persuasion', 'Sleight of Hand', 'Stealth'], }, ], 'Skill': [ {'name': 'Acrobatics'}, {'name': 'Animal Handling'}, {'name': 'Athletics'}, {'name': 'Deception'}, {'name': 'History'}, {'name': 'Insight'}, {'name': 'Intimidation'}, {'name': 'Investigation'}, {'name': 'Perception'}, {'name': 'Performance'}, {'name': 'Persuasion'}, {'name': 'Sleight of Hand'}, {'name': 'Stealth'}, {'name': 'Survival'}, ], 'Ancestry': [ {'id': 1, 'name': 'human', 'creature_type': 'humanoid'}, {'id': 2, 'name': 'dragonborn', 'creature_type': 'humanoid'}, {'id': 3, 'name': 'tiefling', 'creature_type': 'humanoid'}, {'id': 4, 'name': 'elf', 'creature_type': 'humanoid'}, ], 'AncestryTrait': [ {'id': 1, 'name': '+1 to All Ability Scores', }, {'id': 2, 'name': 'Breath Weapon', }, {'id': 3, 'name': 'Darkvision', }, ], 'AncestryTraitMap': [ {'ancestry_id': 1, 'ancestry_trait_id': 1, 'level': 1}, # human +1 to scores {'ancestry_id': 2, 'ancestry_trait_id': 2, 'level': 1}, # dragonborn breath weapon {'ancestry_id': 3, 'ancestry_trait_id': 3, 'level': 1}, # tiefling darkvision {'ancestry_id': 2, 'ancestry_trait_id': 2, 'level': 1}, # elf darkvision ], 'CharacterClassMap': [ { 'character_id': 1, 'character_class_id': 1, 'level': 2, }, { 'character_id': 1, 'character_class_id': 2, 'level': 3, }, ], 'Character': [ { 'id': 1, 'name': 'Sabetha', 'ancestry_id': 1, 'armor_class': 10, 'max_hit_points': 14, 'hit_points': 14, 'temp_hit_points': 0, 'speed': 30, 'str': 16, 'dex': 12, 'con': 18, 'int': 11, 'wis': 12, 'cha': 8, 'proficiencies': 'all armor, all shields, simple weapons, martial weapons', 'saving_throws': ['STR', 'CON'], 'skills': ['Acrobatics', 'Animal Handling'], }, ], 'ClassAttribute': [ {'id': 1, 'name': 'Fighting Style'}, {'id': 2, 'name': 'Another Attribute'}, ], 'ClassAttributeOption': [ {'id': 1, 'attribute_id': 1, 'name': 'Archery'}, {'id': 2, 'attribute_id': 1, 'name': 'Battlemaster'}, {'id': 3, 'attribute_id': 2, 'name': 'Another Option 1'}, {'id': 4, 'attribute_id': 2, 'name': 'Another Option 2'}, ], 'ClassAttributeMap': [ {'class_attribute_id': 1, 'character_class_id': 1, 'level': 2}, # Fighter: Fighting Style {'class_attribute_id': 2, 'character_class_id': 1, 'level': 1}, # Fighter: Another Attr ], 'CharacterClassAttributeMap': [ {'character_id': 1, 'class_attribute_id': 2, 'option_id': 4}, # Sabetha, another option, option 2 {'character_id': 1, 'class_attribute_id': 1, 'option_id': 1}, # Sabetha, fighting style, archery ], 'Modifier': [ # Humans {'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'str'}, {'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'dex'}, {'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'con'}, {'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'int'}, {'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'wis'}, {'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'cha'}, # Dragonborn {'source_table_name': 'ancestry_trait', 'source_table_id': 2, 'value': '60', 'type': 'attribute ', 'target': 'Darkvision'}, {'source_table_name': 'ancestry_trait', 'source_table_id': 2, 'value': '+1', 'type': 'stat', 'target': ''}, {'source_table_name': 'ancestry_trait', 'source_table_id': 2, 'value': '+1', 'type': 'stat', 'target': ''}, # Fighting Style: Archery {'source_table_name': 'class_attribute', 'source_table_id': 1, 'value': '+2', 'type': 'weapon ', 'target': 'ranged'}, ], } def bootstrap(): """ Initialize the database with source data. Idempotent; will skip anything that already exists. """ db.init() for table, records in data.items(): model = getattr(schema, table) for rec in records: obj = model(**rec) try: with db.transaction(): db.session.add(obj) logging.info(f"Created {table} {obj}") except IntegrityError as e: if 'UNIQUE constraint failed' in str(e): logging.info(f"Skipping existing {table} {obj}") continue raise