def _build_session(self): """ Construct a SQLAlchemy Session() context object. To avoid having to pass session objects around between Barbados (backend) and Jamaica (frontend) this function will attempt to determine if we're running inside of a Flask context at the time of call (scoped session per-request) and use that session. If we're not then generate one 'cause we're probably running in a script or something weird like that. Flask sessions will close at the end of the request or when explicitly told to so to prevent double-committing (which isn't a problem, it just resets the session an extra time) this will feed back into the caller. https://docs.sqlalchemy.org/en/13/orm/session_basics.html#closing :return: Session context object, Boolean of whether to trigger a commit or not. """ commit = False try: from flask_sqlalchemy_session import current_session as session if not session: raise RuntimeError LogService.debug("Using Flask session") except RuntimeError as e: session = self.ScopedSession() commit = True LogService.debug("Using thread scoped session") return session, commit
def delete(self): LogService.debug("Deleting old data from database") with self.pgconn.get_session() as session: deleted = session.query(self.model).delete() LogService.info("Deleted %s" % deleted) Indexes.rebuild(ListIndex)
def get(endpoint, args): LogService.debug("Getting %s" % args.slug) if args.slug == 'all': result = requests.get(endpoint) else: result = requests.get("%s/%s" % (endpoint, args.slug)) print(json.dumps(result.json())) Resource._handle_error(result)
def init(self): """ Re-initialize all indexes. This calls rebuild on every registered index class. There be dragons here. :return: None """ for name in self._indexes.keys(): LogService.debug("Init on %s" % name) try: self.rebuild(self._indexes.get(name)) except NotFoundError or KeyError or AttributeError as e: LogService.warning("Error re-initing index %s: %s" % (name, e))
def _build_tree(self, passes, root=root_node): """ Construct the treelib.Tree object. :param passes: Number of iterations to construct to tree in. :param root: String ID of the root node of the tree. :return: Completed treelib.Tree object """ tree = Tree() with DatabaseService.get_session() as session: tree.create_node(root, root) for i in IngredientModel.get_by_kind(session, CategoryKind): i = IngredientFactory.model_to_obj(i) tree.create_node(i.slug, i.slug, parent=root, data=i) ingredients_to_place = [ IngredientFactory.model_to_obj(item) for item in IngredientModel.get_usable_ingredients(session) ] for idx in range(1, passes + 1): LogService.debug("Pass %i/%i" % (idx, passes)) # If you remove items from a list you're iterating over you # dynamically change the indexing, making things get out of whack. # You can get around this by making a copy of the list and iterating # over that while you remove items from the original list. # https://thispointer.com/python-remove-elements-from-a-list-while-iterating/ for i in ingredients_to_place.copy(): try: tree.create_node(i.slug, i.slug, parent=i.parent, data=i) # This is to maintain a list of all index elements since finding those # is somewhat hard after the fact. if i.kind == IndexKind: self._index_node_ids.append(i.slug) ingredients_to_place.remove(i) except NodeIDAbsentError: LogService.debug("skipping %s (Attempt %i/%s)" % (i.slug, idx, passes)) if len(ingredients_to_place) == 0: LogService.info("All done after pass %i" % idx) break LogService.info("Tree has len %i" % len(tree)) return tree
def _handle_error(result): """ Parse an HTTP request for success/failure. Return a count of the success. :param result: :return: Integer count of success (THIS IS NOT A RETURN CODE!) """ try: result.raise_for_status() LogService.debug('Success!') return 1 except requests.exceptions.RequestException as e: LogService.error("Error handling URL: %i" % result.status_code) LogService.error(result.request.body) LogService.error(result.json().get('message')) LogService.error(result.json().get('details')) return 0
def delete(self, cocktail=None, delete_all=False): if cocktail: with self.pgconn.get_session() as session: existing = session.query(CocktailModel).get(cocktail.slug) if existing: LogService.debug("Deleting %s" % existing.slug) deleted = session.delete(existing) return if delete_all is True: with self.pgconn.get_session() as session: LogService.debug("Deleting all CocktailModel") deleted = session.query(CocktailModel).delete() LogService.info("Deleted %s from %s" % (deleted, CocktailModel.__tablename__)) Indexes.rebuild(RecipeIndex)
def get_session(self): """ Provide a valid SQLAlchemy Session for use in a context. Example: with get_session() as session: result = session.query(CocktailModel).get('mai-tai') :return: None """ session, commit = self._build_session() try: yield session if commit: session.commit() except Exception: session.rollback() raise finally: LogService.debug("Database with() context complete.")
def event_end_session(session, transaction): LogService.debug("Closing database session: %s" % session)
def event_new_session(session, transaction, connection): LogService.debug("Opening new database session: %s" % session)