No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

datasource.py 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # -*- coding: utf-8 -*-
  2. import pymongo
  3. from pymongo import MongoClient
  4. from pymongo.errors import BulkWriteError
  5. import urllib
  6. import lodel.datasource.mongodb.utils as utils
  7. from lodel.datasource.generic.datasource import GenericDataSource
  8. class MongoDbDataSourceError(Exception):
  9. pass
  10. class MongoDbDataSource(GenericDataSource):
  11. MANDATORY_CONNECTION_ARGS = ('host', 'port', 'login', 'password', 'dbname')
  12. ## @brief Instanciates a Database object given a connection name
  13. # @param connection_name str
  14. def __init__(self, connection_name='default'):
  15. connection_args = self._get_connection_args(connection_name)
  16. login, password, host, port, dbname = MongoDbDataSource._check_connection_args(connection_args)
  17. # Creating of the connection
  18. connection_string = 'mongodb://%s:%s@%s:%s' % (login, password, host, port)
  19. self.connection = MongoClient(connection_string)
  20. # Getting the database
  21. self.database = self.connection[dbname]
  22. ## @brief Gets the settings given a connection name
  23. # @param connection_name str
  24. # @return dict
  25. # @TODO Change the return value using the Lodel 2 settings module
  26. def _get_connection_args(self, connection_name):
  27. return {
  28. 'host': 'localhost',
  29. 'port': 27017,
  30. 'login': 'login', # TODO modifier la valeur
  31. 'password': 'password', # TODO modifier la valeur
  32. 'dbname': 'lodel'
  33. }
  34. ## @brief checks if the connection args are valid and complete
  35. # @param connection_args dict
  36. # @return bool
  37. # @todo checks on the argument types can be added here
  38. @classmethod
  39. def _check_connection_args(cls, connection_args):
  40. errors = []
  41. for connection_arg in cls.MANDATORY_CONNECTION_ARGS:
  42. if connection_arg not in connection_args:
  43. errors.append("Datasource connection error : %s parameter is missing." % connection_arg)
  44. if len(errors) > 0 :
  45. raise MongoDbDataSourceError("\r\n-".join(errors))
  46. return (connection_args['login'], urllib.quote_plus(connection_args['password']), connection_args['host'],
  47. connection_args['port'], connection_args['dbname'])
  48. ## @brief returns a selection of documents from the datasource
  49. # @param target_cls Emclass
  50. # @param field_list list
  51. # @param filters list : List of filters
  52. # @param rel_filters list : List of relational filters
  53. # @param order list : List of column to order. ex: order = [('title', 'ASC'),]
  54. # @param group list : List of tupple representing the column to group together. ex: group = [('title', 'ASC'),]
  55. # @param limit int : Number of records to be returned
  56. # @param offset int: used with limit to choose the start record
  57. # @param instanciate bool : If true, the records are returned as instances, else they are returned as dict
  58. # @return list
  59. # @todo Implement the grouping
  60. # @todo Implement the relations
  61. def select(self, target_cls, field_list, filters, rel_filters=None, order=None, group=None, limit=None, offset=0,
  62. instanciate=True):
  63. collection_name = utils.object_collection_name(target_cls.__class__)
  64. collection = self.database[collection_name]
  65. query_filters = utils.parse_query_filters(filters)
  66. query_result_ordering = utils.parse_query_order(order) if order is not None else None
  67. results_field_list = None if len(field_list) == 0 else field_list
  68. limit = limit if limit is not None else 0
  69. cursor = collection.find(
  70. filter=query_filters,
  71. projection=results_field_list,
  72. skip=offset,
  73. limit=limit,
  74. sort=query_result_ordering
  75. )
  76. results = list()
  77. for document in cursor:
  78. results.append(document)
  79. return results
  80. ## @brief Deletes one record defined by its uid
  81. # @param target_cls Emclass : class of the record to delete
  82. # @param uid dict|list : a dictionary of fields and values composing the unique identifier of the record or a list of several dictionaries
  83. # @return int : number of deleted records
  84. # @TODO check the content of the result.raw_result property depending on the informations to return
  85. # @TODO Implement the error management
  86. def delete(self, target_cls, uid):
  87. if isinstance(uid, dict):
  88. uid = [uid]
  89. collection_name = utils.object_collection_name(target_cls.__class__)
  90. collection = self.database[collection_name]
  91. result = collection.delete_many(uid)
  92. return result.deleted_count
  93. ## @brief updates one or a list of records
  94. # @param target_cls Emclass : class of the object to insert
  95. # @param uids list : list of uids to update
  96. # @param datas dict : datas to update (new values)
  97. # @return int : Number of updated records
  98. # @todo check if the values need to be parsed
  99. def update(self, target_cls, uids, **datas):
  100. if not isinstance(uids, list):
  101. uids = [uids]
  102. collection_name = utils.object_collection_name(target_cls.__class__)
  103. collection = self.database[collection_name]
  104. results = collection.update_many({'uid': {'$in': uids}}, datas)
  105. return results.modified_count()
  106. ## @brief Inserts a record in a given collection
  107. # @param target_cls Emclass : class of the object to insert
  108. # @param datas dict : datas to insert
  109. # @return bool
  110. # @TODO Implement the error management
  111. def insert(self, target_cls, **datas):
  112. collection_name = utils.object_collection_name(target_cls.__class__)
  113. collection = self.database[collection_name]
  114. result = collection.insert_one(datas)
  115. return len(result.inserted_id)
  116. ## @brief Inserts a list of records in a given collection
  117. # @param target_cls Emclass : class of the objects inserted
  118. # @param datas_list
  119. # @return list : list of the inserted records' ids
  120. # @TODO Implement the error management
  121. def insert_multi(self, target_cls, datas_list):
  122. collection_name = utils.object_collection_name(target_cls.__class__)
  123. collection = self.database[collection_name]
  124. result = collection.insert_many(datas_list)
  125. return len(result.inserted_ids)