Remove and ignore code_snippets.rst as it's auto-generated.
parent
7d08e42bbe
commit
14ced20db0
|
@ -0,0 +1 @@
|
|||
code_snippets.py
|
|
@ -1,590 +0,0 @@
|
|||
*************
|
||||
Code Snippets
|
||||
*************
|
||||
|
||||
|
||||
This document contains code for some of the important classes, listed as
|
||||
below:
|
||||
|
||||
* PgAdminModule_
|
||||
* NodeView_
|
||||
* BaseDriver_
|
||||
* BaseConnection_
|
||||
|
||||
|
||||
.. _PgAdminModule:
|
||||
|
||||
PgAdminModule
|
||||
*************
|
||||
|
||||
|
||||
PgAdminModule is inherted from Flask.Blueprint module.
|
||||
This module defines a set of methods, properties and attributes, that every module should implement.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class PgAdminModule(Blueprint):
|
||||
"""
|
||||
Base class for every PgAdmin Module.
|
||||
|
||||
This class defines a set of method and attributes that
|
||||
every module should implement.
|
||||
"""
|
||||
|
||||
def __init__(self, name, import_name, **kwargs):
|
||||
kwargs.setdefault('url_prefix', '/' + name)
|
||||
kwargs.setdefault('template_folder', 'templates')
|
||||
kwargs.setdefault('static_folder', 'static')
|
||||
self.submodules = []
|
||||
|
||||
super(PgAdminModule, self).__init__(name, import_name, **kwargs)
|
||||
|
||||
def create_module_preference():
|
||||
# Create preference for each module by default
|
||||
if hasattr(self, 'LABEL'):
|
||||
self.preference = Preferences(self.name, self.LABEL)
|
||||
else:
|
||||
self.preference = Preferences(self.name, None)
|
||||
|
||||
self.register_preferences()
|
||||
|
||||
# Create and register the module preference object and preferences for
|
||||
# it just before the first request
|
||||
self.before_app_first_request(create_module_preference)
|
||||
|
||||
def register_preferences(self):
|
||||
pass
|
||||
|
||||
def register(self, app, options, first_registration=False):
|
||||
"""
|
||||
Override the default register function to automagically register
|
||||
sub-modules at once.
|
||||
"""
|
||||
if first_registration:
|
||||
self.submodules = list(app.find_submodules(self.import_name))
|
||||
|
||||
super(PgAdminModule, self).register(app, options, first_registration)
|
||||
|
||||
for module in self.submodules:
|
||||
app.register_blueprint(module)
|
||||
|
||||
def get_own_stylesheets(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the stylesheets used by this module, not including any
|
||||
stylesheet needed by the submodules.
|
||||
"""
|
||||
return []
|
||||
|
||||
def get_own_messages(self):
|
||||
"""
|
||||
Returns:
|
||||
dict: the i18n messages used by this module, not including any
|
||||
messages needed by the submodules.
|
||||
"""
|
||||
return dict()
|
||||
|
||||
def get_own_javascripts(self):
|
||||
"""
|
||||
Returns:
|
||||
list: the javascripts used by this module, not including
|
||||
any script needed by the submodules.
|
||||
"""
|
||||
return []
|
||||
|
||||
def get_own_menuitems(self):
|
||||
"""
|
||||
Returns:
|
||||
dict: the menuitems for this module, not including
|
||||
any needed from the submodules.
|
||||
"""
|
||||
return defaultdict(list)
|
||||
|
||||
def get_panels(self):
|
||||
"""
|
||||
Returns:
|
||||
list: a list of panel objects to add
|
||||
"""
|
||||
return []
|
||||
|
||||
@property
|
||||
def stylesheets(self):
|
||||
stylesheets = self.get_own_stylesheets()
|
||||
for module in self.submodules:
|
||||
stylesheets.extend(module.stylesheets)
|
||||
return stylesheets
|
||||
|
||||
@property
|
||||
def messages(self):
|
||||
res = self.get_own_messages()
|
||||
|
||||
for module in self.submodules:
|
||||
res.update(module.messages)
|
||||
return res
|
||||
|
||||
@property
|
||||
def javascripts(self):
|
||||
javascripts = self.get_own_javascripts()
|
||||
for module in self.submodules:
|
||||
javascripts.extend(module.javascripts)
|
||||
return javascripts
|
||||
|
||||
@property
|
||||
def menu_items(self):
|
||||
menu_items = self.get_own_menuitems()
|
||||
for module in self.submodules:
|
||||
for key, value in module.menu_items.items():
|
||||
menu_items[key].extend(value)
|
||||
menu_items = dict((key, sorted(value, key=attrgetter('priority')))
|
||||
for key, value in menu_items.items())
|
||||
return menu_items
|
||||
|
||||
|
||||
.. _NodeView:
|
||||
|
||||
NodeView
|
||||
********
|
||||
|
||||
|
||||
NodeView class helps exposing basic REST APIs for different operations used by
|
||||
pgAdmin Browser. The basic idea has been taken from the `Flask's MethodView
|
||||
<http://flask.pocoo.org/docs/0.10/api/#flask.views.MethodView>`_ class. Because
|
||||
- we need a lot more operations (not, just CRUD), we can not use it directly.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class NodeView(with_metaclass(MethodViewType, View)):
|
||||
"""
|
||||
A PostgreSQL Object has so many operaions/functions apart from CRUD
|
||||
(Create, Read, Update, Delete):
|
||||
i.e.
|
||||
- Reversed Engineered SQL
|
||||
- Modified Query for parameter while editing object attributes
|
||||
i.e. ALTER TABLE ...
|
||||
- Statistics of the objects
|
||||
- List of dependents
|
||||
- List of dependencies
|
||||
- Listing of the children object types for the certain node
|
||||
It will used by the browser tree to get the children nodes
|
||||
|
||||
This class can be inherited to achieve the diffrent routes for each of the
|
||||
object types/collections.
|
||||
|
||||
OPERATION | URL | HTTP Method | Method
|
||||
---------------+-----------------------------+-------------+--------------
|
||||
List | /obj/[Parent URL]/ | GET | list
|
||||
Properties | /obj/[Parent URL]/id | GET | properties
|
||||
Create | /obj/[Parent URL]/ | POST | create
|
||||
Delete | /obj/[Parent URL]/id | DELETE | delete
|
||||
Update | /obj/[Parent URL]/id | PUT | update
|
||||
|
||||
SQL (Reversed | /sql/[Parent URL]/id | GET | sql
|
||||
Engineering) |
|
||||
SQL (Modified | /msql/[Parent URL]/id | GET | modified_sql
|
||||
Properties) |
|
||||
|
||||
Statistics | /stats/[Parent URL]/id | GET | statistics
|
||||
Dependencies | /dependency/[Parent URL]/id | GET | dependencies
|
||||
Dependents | /dependent/[Parent URL]/id | GET | dependents
|
||||
|
||||
Nodes | /nodes/[Parent URL]/ | GET | nodes
|
||||
Current Node | /nodes/[Parent URL]/id | GET | node
|
||||
|
||||
Children | /children/[Parent URL]/id | GET | children
|
||||
|
||||
NOTE:
|
||||
Parent URL can be seen as the path to identify the particular node.
|
||||
|
||||
i.e.
|
||||
In order to identify the TABLE object, we need server -> database -> schema
|
||||
information.
|
||||
"""
|
||||
operations = dict({
|
||||
'obj': [
|
||||
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
|
||||
{'get': 'list', 'post': 'create'}
|
||||
],
|
||||
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
|
||||
'sql': [{'get': 'sql'}],
|
||||
'msql': [{'get': 'modified_sql'}],
|
||||
'stats': [{'get': 'statistics'}],
|
||||
'dependency': [{'get': 'dependencies'}],
|
||||
'dependent': [{'get': 'dependents'}],
|
||||
'children': [{'get': 'children'}],
|
||||
'module.js': [{}, {}, {'get': 'module_js'}]
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def generate_ops(cls):
|
||||
cmds = []
|
||||
for op in cls.operations:
|
||||
idx = 0
|
||||
for ops in cls.operations[op]:
|
||||
meths = []
|
||||
for meth in ops:
|
||||
meths.append(meth.upper())
|
||||
if len(meths) > 0:
|
||||
cmds.append({
|
||||
'cmd': op, 'req': (idx == 0),
|
||||
'with_id': (idx != 2), 'methods': meths
|
||||
})
|
||||
idx += 1
|
||||
return cmds
|
||||
|
||||
# Inherited class needs to modify these parameters
|
||||
node_type = None
|
||||
# This must be an array object with attributes (type and id)
|
||||
parent_ids = []
|
||||
# This must be an array object with attributes (type and id)
|
||||
ids = []
|
||||
|
||||
@classmethod
|
||||
def get_node_urls(cls):
|
||||
assert cls.node_type is not None, \
|
||||
"Please set the node_type for this class ({0})".format(
|
||||
str(cls.__class__.__name__))
|
||||
common_url = '/'
|
||||
for p in cls.parent_ids:
|
||||
common_url += '<{0}:{1}>/'.format(str(p['type']), str(p['id']))
|
||||
|
||||
id_url = None
|
||||
for p in cls.ids:
|
||||
id_url = '{0}<{1}:{2}>'.format(common_url if not id_url else id_url,
|
||||
p['type'], p['id'])
|
||||
|
||||
return id_url, common_url
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.cmd = kwargs['cmd']
|
||||
|
||||
# Check the existance of all the required arguments from parent_ids
|
||||
# and return combination of has parent arguments, and has id arguments
|
||||
def check_args(self, **kwargs):
|
||||
has_id = has_args = True
|
||||
for p in self.parent_ids:
|
||||
if p['id'] not in kwargs:
|
||||
has_args = False
|
||||
break
|
||||
|
||||
for p in self.ids:
|
||||
if p['id'] not in kwargs:
|
||||
has_id = False
|
||||
break
|
||||
|
||||
return has_args, has_id and has_args
|
||||
|
||||
def dispatch_request(self, *args, **kwargs):
|
||||
meth = flask.request.method.lower()
|
||||
if meth == 'head':
|
||||
meth = 'get'
|
||||
|
||||
assert self.cmd in self.operations, \
|
||||
"Unimplemented command ({0}) for {1}".format(
|
||||
self.cmd,
|
||||
str(self.__class__.__name__)
|
||||
)
|
||||
|
||||
has_args, has_id = self.check_args(**kwargs)
|
||||
|
||||
assert (self.cmd in self.operations and
|
||||
(has_id and len(self.operations[self.cmd]) > 0 and
|
||||
meth in self.operations[self.cmd][0]) or
|
||||
(not has_id and len(self.operations[self.cmd]) > 1 and
|
||||
meth in self.operations[self.cmd][1]) or
|
||||
(len(self.operations[self.cmd]) > 2 and
|
||||
meth in self.operations[self.cmd][2])), \
|
||||
"Unimplemented method ({0}) for command ({1}), which {2} an id".format(
|
||||
meth, self.cmd,
|
||||
'requires' if has_id else 'does not require'
|
||||
)
|
||||
|
||||
meth = self.operations[self.cmd][0][meth] if has_id else \
|
||||
self.operations[self.cmd][1][meth] if has_args and \
|
||||
meth in self.operations[self.cmd][1] else \
|
||||
self.operations[self.cmd][2][meth]
|
||||
|
||||
method = getattr(self, meth, None)
|
||||
|
||||
if method is None:
|
||||
return make_json_response(
|
||||
status=406,
|
||||
success=0,
|
||||
errormsg=gettext(
|
||||
"Unimplemented method ({0}) for this url ({1})".format(
|
||||
meth, flask.request.path)
|
||||
)
|
||||
)
|
||||
|
||||
return method(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def register_node_view(cls, blueprint):
|
||||
cls.blueprint = blueprint
|
||||
id_url, url = cls.get_node_urls()
|
||||
|
||||
commands = cls.generate_ops()
|
||||
|
||||
for c in commands:
|
||||
if c['with_id']:
|
||||
blueprint.add_url_rule(
|
||||
'/{0}{1}'.format(
|
||||
c['cmd'], id_url if c['req'] else url
|
||||
),
|
||||
view_func=cls.as_view(
|
||||
'{0}{1}'.format(
|
||||
c['cmd'], '_id' if c['req'] else ''
|
||||
),
|
||||
cmd=c['cmd']
|
||||
),
|
||||
methods=c['methods']
|
||||
)
|
||||
else:
|
||||
blueprint.add_url_rule(
|
||||
'/{0}'.format(c['cmd']),
|
||||
view_func=cls.as_view(
|
||||
'{0}'.format(c['cmd']), cmd=c['cmd']
|
||||
),
|
||||
methods=c['methods']
|
||||
)
|
||||
|
||||
def module_js(self, **kwargs):
|
||||
"""
|
||||
This property defines (if javascript) exists for this node.
|
||||
Override this property for your own logic.
|
||||
"""
|
||||
return flask.make_response(
|
||||
flask.render_template(
|
||||
"{0}/js/{0}.js".format(self.node_type)
|
||||
),
|
||||
200, {'Content-Type': 'application/x-javascript'}
|
||||
)
|
||||
|
||||
def children(self, *args, **kwargs):
|
||||
"""Build a list of treeview nodes from the child nodes."""
|
||||
children = []
|
||||
|
||||
for module in self.blueprint.submodules:
|
||||
children.extend(module.get_nodes(*args, **kwargs))
|
||||
|
||||
return make_json_response(data=children)
|
||||
|
||||
|
||||
.. _BaseDriver:
|
||||
|
||||
BaseDriver
|
||||
**********
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class BaseDriver(object):
|
||||
"""
|
||||
class BaseDriver(object):
|
||||
|
||||
This is a base class for different server types.
|
||||
Inherit this class to implement different type of database driver
|
||||
implementation.
|
||||
|
||||
(For PostgreSQL/Postgres Plus Advanced Server, we will be using psycopg2)
|
||||
|
||||
Abstract Properties:
|
||||
-------- ----------
|
||||
* Version (string):
|
||||
Current version string for the database server
|
||||
|
||||
Abstract Methods:
|
||||
-------- -------
|
||||
* get_connection(*args, **kwargs)
|
||||
- It should return a Connection class object, which may/may not be
|
||||
connected to the database server.
|
||||
|
||||
* release_connection(*args, **kwargs)
|
||||
- Implement the connection release logic
|
||||
|
||||
* gc()
|
||||
- Implement this function to release the connections assigned in the
|
||||
session, which has not been pinged from more than the idle timeout
|
||||
configuration.
|
||||
"""
|
||||
|
||||
@abstractproperty
|
||||
def Version(cls):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_connection(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def release_connection(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def gc(self):
|
||||
pass
|
||||
|
||||
|
||||
.. _BaseConnection:
|
||||
|
||||
BaseConnection
|
||||
**************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class BaseConnection(object):
|
||||
"""
|
||||
class BaseConnection(object)
|
||||
|
||||
It is a base class for database connection. A different connection
|
||||
drive must implement this to expose abstract methods for this server.
|
||||
|
||||
General idea is to create a wrapper around the actual driver
|
||||
implementation. It will be instantiated by the driver factory
|
||||
basically. And, they should not be instantiated directly.
|
||||
|
||||
|
||||
Abstract Methods:
|
||||
-------- -------
|
||||
* connect(**kwargs)
|
||||
- Define this method to connect the server using that particular driver
|
||||
implementation.
|
||||
|
||||
* execute_scalar(query, params, formatted_exception_msg)
|
||||
- Implement this method to execute the given query and returns single
|
||||
datum result.
|
||||
|
||||
* execute_async(query, params, formatted_exception_msg)
|
||||
- Implement this method to execute the given query asynchronously and returns result.
|
||||
|
||||
* execute_void(query, params, formatted_exception_msg)
|
||||
- Implement this method to execute the given query with no result.
|
||||
|
||||
* execute_2darray(query, params, formatted_exception_msg)
|
||||
- Implement this method to execute the given query and returns the result
|
||||
as a 2 dimensional array.
|
||||
|
||||
* execute_dict(query, params, formatted_exception_msg)
|
||||
- Implement this method to execute the given query and returns the result
|
||||
as an array of dict (column name -> value) format.
|
||||
|
||||
* connected()
|
||||
- Implement this method to get the status of the connection. It should
|
||||
return True for connected, otherwise False
|
||||
|
||||
* reset()
|
||||
- Implement this method to reconnect the database server (if possible)
|
||||
|
||||
* transaction_status()
|
||||
- Implement this method to get the transaction status for this
|
||||
connection. Range of return values different for each driver type.
|
||||
|
||||
* ping()
|
||||
- Implement this method to ping the server. There are times, a connection
|
||||
has been lost, but - the connection driver does not know about it. This
|
||||
can be helpful to figure out the actual reason for query failure.
|
||||
|
||||
* _release()
|
||||
- Implement this method to release the connection object. This should not
|
||||
be directly called using the connection object itself.
|
||||
|
||||
NOTE: Please use BaseDriver.release_connection(...) for releasing the
|
||||
connection object for better memory management, and connection pool
|
||||
management.
|
||||
|
||||
* _wait(conn)
|
||||
- Implement this method to wait for asynchronous connection to finish the
|
||||
execution, hence - it must be a blocking call.
|
||||
|
||||
* _wait_timeout(conn, time)
|
||||
- Implement this method to wait for asynchronous connection with timeout.
|
||||
This must be a non blocking call.
|
||||
|
||||
* poll(formatted_exception_msg)
|
||||
- Implement this method to poll the data of query running on asynchronous
|
||||
connection.
|
||||
|
||||
* cancel_transaction(conn_id, did=None)
|
||||
- Implement this method to cancel the running transaction.
|
||||
|
||||
* messages()
|
||||
- Implement this method to return the list of the messages/notices from
|
||||
the database server.
|
||||
|
||||
* rows_affected()
|
||||
- Implement this method to get the rows affected by the last command
|
||||
executed on the server.
|
||||
"""
|
||||
|
||||
ASYNC_OK = 1
|
||||
ASYNC_READ_TIMEOUT = 2
|
||||
ASYNC_WRITE_TIMEOUT = 3
|
||||
ASYNC_NOT_CONNECTED = 4
|
||||
ASYNC_EXECUTION_ABORTED = 5
|
||||
|
||||
@abstractmethod
|
||||
def connect(self, **kwargs):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def execute_scalar(self, query, params=None, formatted_exception_msg=False):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def execute_async(self, query, params=None, formatted_exception_msg=True):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def execute_void(self, query, params=None, formatted_exception_msg=False):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def execute_2darray(self, query, params=None, formatted_exception_msg=False):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def execute_dict(self, query, params=None, formatted_exception_msg=False):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def connected(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def reset(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def transaction_status(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def ping(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _release(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _wait(self, conn):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _wait_timeout(self, conn, time):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def poll(self, formatted_exception_msg=True):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def status_message(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def rows_affected(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def cancel_transaction(self, conn_id, did=None):
|
||||
pass
|
Loading…
Reference in New Issue