def empty_collection(collection_name: str, db: StandardDatabase, edge: bool = False): try: db.delete_collection(collection_name) db.create_collection(collection_name, edge=edge) except CollectionDeleteError: print( f"couldn't remove collection: {collection_name}. It probably doesn't exist." ) except CollectionCreateError: print(f"couldn't create collection: {collection_name}")
def save(db: StandardDatabase, instance: GameInstance): """ save a game instance :param db: connection :param instance: game """ logger.info(f'save called for {instance.id} ({instance.game.title})') if not db.has_collection('instances'): logger.info('creating collection instances') db.create_collection('instances') col = db.collection('instances') txn_db = db.begin_transaction(read=col.name, write=col.name) txn_col = txn_db.collection('instances') txn_col.insert(json.dumps(instance, cls=MarugotoEncoder)) txn_db.commit_transaction()
def create(db: StandardDatabase, email, password, salt) -> Player: """ create a new player :param db: connection :param email: mail :param password: plain text password :param salt: encryption salt :return: Player """ if not db.has_collection('players'): logger.info('creating collection players') db.create_collection('players') player = Player(email, hash_password(password, salt)) col = db.collection('players') col.insert({ '_key': player.id.hex, 'mail': player.email, 'password': player.password, 'tokens': [] }) return player
def create_collection(db: StandardDatabase, name: str, unique_fields: Tuple, _schema: Dict): if not db.has_collection(name): collection = db.create_collection(name=name, schema=_schema) collection.add_hash_index(fields=unique_fields, unique=True)
def create(db: StandardDatabase, game: Game, creator=None): """ save a game to the database :param db: connection :param game: target :param creator: creator of the game """ logger.info(f'create called for {game.title}') if not db.has_collection('games'): logger.info(f'games collection does not exist, creating it.') db.create_collection('games') db_games = db.collection('games') if db_games.find({'key': game.title}): logger.warning(f'{game.title} already in metadata') raise GameStateException(f'{game.title} already in metadata') if db.has_graph(game.title): logger.warning(f'{game.title} already defined') raise GameStateException(f'{game.title} already defined') if not nx.is_directed_acyclic_graph(game.graph): logger.warning(f'{game.title} is not acyclic') raise GameStateException(f'{game.title} is not acyclic') if not game.start_is_set(): logger.warning(f'{game.title} has no starting point') raise GameStateException(f'{game.title} has no starting point') db_game_graph = db.create_graph(f'game_{game.title}') if not db_game_graph.has_vertex_collection('waypoints'): logger.info(f'waypoints vertex collection does not exist, creating it.') db_game_graph.create_vertex_collection('waypoints') path = db_game_graph.create_edge_definition( edge_collection='path', from_vertex_collections=['waypoints'], to_vertex_collections=['waypoints'] ) # add all game nodes for waypoint_vertex in set(game.start.all_path_nodes()): logger.debug(f'inserting waypoint vertex {repr(waypoint_vertex)}') db_game_graph.insert_vertex('waypoints', json.dumps(waypoint_vertex, cls=MarugotoEncoder)) # tasks as documents if not db.has_collection('tasks'): logger.info(f'tasks collection does not exist, creating it.') db.create_collection('tasks') tasks = db.collection('tasks') # dialogs metadata if not db.has_collection('dialogs'): logger.info(f'dialogs does not exist, creating it.') db.create_collection('dialogs') db_dialogs = db.collection('dialogs') # npc dialog metadata if not db.has_collection('npcs'): logger.info(f'npcs collection does not exist, creating it.') db.create_collection('npcs') db_npcs = db.collection('npcs') for npc in game.npcs: if db_npcs.find({'_key': f'{game.title}-{npc.first_name}-{npc.last_name}'}): logger.warning(f'dialog {game.title}-{npc.first_name}-{npc.last_name} already in metadata') raise GameStateException(f'dialog {game.title}-{npc.first_name}-{npc.last_name} already in metadata') logger.debug(f'inserting npc {game.title}-{npc.first_name}-{npc.last_name} with dialog {npc.dialog.id.hex}') db_npcs.insert({ '_key': f'{game.title}-{npc.first_name}-{npc.last_name}', 'game': f'game_{game.title}', 'first_name': npc.first_name, 'last_name': npc.last_name, 'salutation': npc.salutation, 'mail': npc.mail, 'image': base64.encodebytes(npc.image) if npc.image else None, 'dialog': npc.dialog.id.hex }) if db_dialogs.find({'_key': npc.dialog.id.hex}): logger.warning(f'dialog {npc.dialog.id} already in metadata') raise GameStateException(f'dialog {npc.dialog.id} already in metadata') if db.has_graph(f'dialog_{npc.dialog.id.hex}'): logger.warning(f'dialog {npc.dialog.id} already defined') raise GameStateException(f'dialog {npc.dialog.id} already defined') if not nx.is_directed_acyclic_graph(npc.dialog.graph): logger.warning(f'dialog {npc.dialog.id} is not acyclic') raise GameStateException(f'dialog {npc.dialog.id} is not acyclic') if not npc.dialog.start_is_set(): logger.warning(f'dialog {npc.dialog.id} has no starting point') raise GameStateException(f'dialog {npc.dialog.id} has no starting point') db_dialog_graph = db.create_graph(f'dialog_{npc.dialog.id.hex}') if not db_dialog_graph.has_vertex_collection('interactions'): logger.debug(f'interaction vertex collection does not exist, creating it.') db_dialog_graph.create_vertex_collection('interactions') conversation = db_dialog_graph.create_edge_definition( edge_collection='conversation', from_vertex_collections=['interactions'], to_vertex_collections=['interactions'] ) # add all dialog nodes for interaction_vertex in set(npc.dialog.start.all_path_nodes()): logger.debug(f'inserting interaction vertex {repr(interaction_vertex)}') db_dialog_graph.insert_vertex('interactions', json.dumps(interaction_vertex, cls=MarugotoEncoder)) dia_visited = {} def dialog_traversal(s, i): """ Walk through the game path from a starting source :param s: starting waypoint for traversal :param i: dict containing identified steps """ for successor in npc.dialog.graph.successors(s): logger.debug(f'successor {repr(successor)} for {repr(s)}') if s not in i.keys(): logger.debug(f'{repr(s)} is new, adding it') i[s] = [] if successor not in i[s]: if successor.task: logger.debug(f'{repr(successor)} has {repr(successor.task)}, adding to tasks') task_dump = json.loads(json.dumps(successor.task, cls=MarugotoEncoder)) task_dump['_key'] = successor.task.id.hex task_dump['for'] = successor.id.hex if not tasks.find(task_dump): tasks.insert(json.dumps(task_dump)) logger.debug(f'inserting interaction edge {repr(s)} to {repr(successor)}') conversation.insert({ '_key': f'{s.id.hex}-{successor.id.hex}', '_from': f'interactions/{s.id.hex}', '_to': f'interactions/{successor.id.hex}' }) dia_visited[s].append(successor) dialog_traversal(successor, i) logger.debug(f'traversing dialog graph for {npc.first_name} {npc.last_name}') dialog_traversal(npc.dialog.start, dia_visited) logger.debug(f'inserting dialog {npc.dialog.id.hex}') db_dialogs.insert({ '_key': npc.dialog.id.hex, 'start': npc.dialog.start.id.hex }) wp_visited = {} def game_traversal(s, i): """ Walk through the game path from a starting source :param s: starting waypoint for traversal :param i: dict containing identified steps """ for successor in game.graph.successors(s): logger.debug(f'successor {repr(successor)} for {repr(s)}') if s not in i.keys(): logger.debug(f'{repr(s)} is new, adding it.') i[s] = [] if successor not in i[s]: for task in successor.tasks: logger.debug(f'{repr(successor)} has {repr(task)}, adding to tasks') task_dump = json.loads(json.dumps(task, cls=MarugotoEncoder)) task_dump['_key'] = task.id.hex task_dump['for'] = successor.id.hex if not tasks.find(task_dump): tasks.insert(json.dumps(task_dump)) logger.debug(f'waypoint interaction edge {repr(s)} to {repr(successor)}') weight = game.graph.edges[s, successor]['weight'] if 'weight' in game.graph.edges[s, successor] and game.graph.edges[s, successor]['weight'] else None path.insert({ '_key': f'{s.id.hex}-{successor.id.hex}', '_from': f'waypoints/{s.id.hex}', '_to': f'waypoints/{successor.id.hex}', 'weight': weight }) wp_visited[s].append(successor) game_traversal(successor, i) logger.debug(f'traversing game graph for {game.title}') game_traversal(game.start, wp_visited) logger.debug(f'inserting game {game.title}') db_games.insert({ '_key': game.title, 'start': game.start.id.hex, 'image': base64.encodebytes(game.image) if game.image else None, 'creator': creator })