We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
list-dids-extended with new metadata plugin currently fails
Motivation
----------
```
rucio set-metadata --did
CTA_LAPP_FREDERIC:cta_data_DL0_ObsId2021_02_22_15_49_11_975413919_TelId0.h
df5 --key ObsID --value 1

rucio get-metadata
CTA_LAPP_FREDERIC:cta_data_DL0_ObsId2021_02_22_15_49_11_975413919_TelId0.h
df5 --plugin ALL
bsID:           1
access_cnt:      None
accessed_at:     None
....

rucio list-dids-extended --filter ObsID=1 CTA_LAPP_FREDERIC:*
/usr/lib/python2.7/site-packages/paramiko/transport.py:33:
CryptographyDeprecationWarning: Python 2 is no longer supported by the
Python core team. Support for it is now deprecated in cryptography, and
will be removed in a future release.
  from cryptography.hazmat.backends import default_backend
2021-02-22 15:58:35,693 ERROR   An unknown exception occurred.
Details: no error information passed (http status code: 500
('internal_server_error', 'server_error', '/o\\', '\xe2\x9c\x97'))
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/rucio/core/did_meta_plugins/json_meta.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright 2013-2021 CERN
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16 # Authors:
17 # - Vincent Garonne <vgaronne@gmail.com>, 2013-2018
18 # - Martin Barisits <martin.barisits@cern.ch>, 2013-2019
19 # - Cedric Serfon <cedric.serfon@cern.ch>, 2013-2020
20 # - Ralph Vigne <ralph.vigne@cern.ch>, 2013
21 # - Mario Lassnig <mario.lassnig@cern.ch>, 2013-2019
22 # - Yun-Pin Sun <winter0128@gmail.com>, 2013
23 # - Thomas Beermann <thomas.beermann@cern.ch>, 2013-2018
24 # - Joaquin Bogado <jbogado@linti.unlp.edu.ar>, 2014-2015
25 # - Wen Guan <wguan.icedew@gmail.com>, 2015
26 # - Hannes Hansen <hannes.jakob.hansen@cern.ch>, 2018-2019
27 # - Tobias Wegner <twegner@cern.ch>, 2019
28 # - Andrew Lister <andrew.lister@stfc.ac.uk>, 2019
29 # - Ruturaj Gujar, <ruturaj.gujar23@gmail.com>, 2019
30 # - Brandon White, <bjwhite@fnal.gov>, 2019
31 # - Aristeidis Fkiaras <aristeidis.fkiaras@cern.ch>, 2020
32 # - Benedikt Ziemons <benedikt.ziemons@cern.ch>, 2020-2021
33 
34 import json as json_lib
35 
36 from six import iteritems
37 from sqlalchemy import String, cast, type_coerce, JSON
38 from sqlalchemy.orm.exc import NoResultFound
39 from sqlalchemy.sql.expression import text
40 
41 from rucio.common import exception
42 from rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin
43 from rucio.db.sqla import models
44 from rucio.db.sqla.session import read_session, transactional_session, stream_session
45 from rucio.db.sqla.util import json_implemented
46 
47 
48 class JSONDidMeta(DidMetaPlugin):
49     """
50     A plugin to store DID metadata on a table on the relational database, using JSON blobs
51     """
52 
53     def __init__(self):
54         super(JSONDidMeta, self).__init__()
55         self.plugin_name = "JSON"
56 
57     @read_session
58     def get_metadata(self, scope, name, session=None):
59         """
60         Get data identifier metadata (JSON)
61 
62         :param scope: The scope name.
63         :param name: The data identifier name.
64         :param session: The database session in use.
65         """
66         if not json_implemented(session=session):
67             raise NotImplementedError
68 
69         try:
70             row = session.query(models.DidMeta).filter_by(scope=scope, name=name).one()
71             meta = getattr(row, 'meta')
72             return json_lib.loads(meta) if session.bind.dialect.name in ['oracle', 'sqlite'] else meta
73         except NoResultFound:
74             raise exception.DataIdentifierNotFound("No generic metadata found for '%(scope)s:%(name)s'" % locals())
75 
76     def set_metadata(self, scope, name, key, value, recursive=False, session=None):
77         self.set_metadata_bulk(scope=scope, name=name, meta={key: value}, recursive=recursive, session=session)
78 
79     @transactional_session
80     def set_metadata_bulk(self, scope, name, meta, recursive=False, session=None):
81         if not json_implemented(session=session):
82             raise NotImplementedError
83 
84         if session.query(models.DataIdentifier).filter_by(scope=scope, name=name).one_or_none() is None:
85             raise exception.DataIdentifierNotFound("Data identifier '%s:%s' not found" % (scope, name))
86 
87         row_did_meta = session.query(models.DidMeta).filter_by(scope=scope, name=name).scalar()
88         if row_did_meta is None:
89             # Add metadata column to new table (if not already present)
90             row_did_meta = models.DidMeta(scope=scope, name=name)
91             row_did_meta.save(session=session, flush=False)
92 
93         existing_meta = {}
94         if hasattr(row_did_meta, 'meta'):
95             if row_did_meta.meta:
96                 existing_meta = row_did_meta.meta
97 
98         # Oracle returns a string instead of a dict
99         if session.bind.dialect.name in ['oracle', 'sqlite'] and existing_meta:
100             existing_meta = json_lib.loads(existing_meta)
101 
102         for key, value in meta.items():
103             existing_meta[key] = value
104 
105         row_did_meta.meta = None
106         session.flush()
107 
108         # Oracle insert takes a string as input
109         if session.bind.dialect.name in ['oracle', 'sqlite']:
110             existing_meta = json_lib.dumps(existing_meta)
111 
112         row_did_meta.meta = existing_meta
113         row_did_meta.save(session=session, flush=True)
114 
115     @transactional_session
116     def delete_metadata(self, scope, name, key, session=None):
117         """
118         Delete a key from the metadata column
119 
120         :param scope: the scope of did
121         :param name: the name of the did
122         :param key: the key to be deleted
123         """
124         if not json_implemented(session=session):
125             raise NotImplementedError
126 
127         try:
128             row = session.query(models.DidMeta).filter_by(scope=scope, name=name).one()
129             existing_meta = getattr(row, 'meta')
130             # Oracle returns a string instead of a dict
131             if session.bind.dialect.name in ['oracle', 'sqlite'] and existing_meta is not None:
132                 existing_meta = json_lib.loads(existing_meta)
133 
134             if key not in existing_meta:
135                 raise exception.KeyNotFound(key)
136 
137             existing_meta.pop(key, None)
138 
139             row.meta = None
140             session.flush()
141 
142             # Oracle insert takes a string as input
143             if session.bind.dialect.name in ['oracle', 'sqlite']:
144                 existing_meta = json_lib.dumps(existing_meta)
145 
146             row.meta = existing_meta
147         except NoResultFound:
148             raise exception.DataIdentifierNotFound("Key not found for data identifier '%(scope)s:%(name)s'" % locals())
149 
150     @stream_session
151     def list_dids(self, scope, filters, type='collection', ignore_case=False, limit=None,
152                   offset=None, long=False, recursive=False, session=None):
153         # Currently for sqlite only add, get and delete is implemented.
154         if not json_implemented(session=session):
155             raise NotImplementedError
156 
157         query = session.query(models.DidMeta)
158         if scope is not None:
159             query = query.filter(models.DidMeta.scope == scope)
160         filters.pop('name', None)
161         for k, v in iteritems(filters):
162             if session.bind.dialect.name == 'oracle':
163                 query = query.filter(text("json_exists(meta,'$.%s?(@==''%s'')')" % (k, v)))
164             else:
165                 query = query.filter(cast(models.DidMeta.meta[k], String) == type_coerce(v, JSON))
166 
167         if long:
168             for row in query.yield_per(5):
169                 yield {
170                     'scope': row.scope,
171                     'name': row.name,
172                     'did_type': 'Info not available in JSON Plugin',
173                     'bytes': 'Info not available in JSON Plugin',
174                     'length': 'Info not available in JSON Plugin'
175                 }
176         else:
177             for row in query.yield_per(5):
178                 yield row.name
179 
180     @read_session
181     def manages_key(self, key, session=None):
182         return json_implemented(session=session)
183 
184     def get_plugin_name(self):
185         """
186         Returns Plugins Name.
187         This can then be used when listing the metadata of did to only provide dids from this plugin.
188         """
189         return self.plugin_name
190
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lib/rucio/core/did_meta_plugins/json_meta.py b/lib/rucio/core/did_meta_plugins/json_meta.py
--- a/lib/rucio/core/did_meta_plugins/json_meta.py
+++ b/lib/rucio/core/did_meta_plugins/json_meta.py
@@ -30,6 +30,7 @@
 # - Brandon White, <bjwhite@fnal.gov>, 2019
 # - Aristeidis Fkiaras <aristeidis.fkiaras@cern.ch>, 2020
 # - Benedikt Ziemons <benedikt.ziemons@cern.ch>, 2020-2021
+# - Rizart Dona <rizart.dona@cern.ch>, 2021
 
 import json as json_lib
 
@@ -160,7 +161,7 @@
         filters.pop('name', None)
         for k, v in iteritems(filters):
             if session.bind.dialect.name == 'oracle':
-                query = query.filter(text("json_exists(meta,'$.%s?(@==''%s'')')" % (k, v)))
+                query = query.filter(text("json_exists(meta,'$?(@.{} == \"{}\")')".format(k, v)))
             else:
                 query = query.filter(cast(models.DidMeta.meta[k], String) == type_coerce(v, JSON))

{"golden_diff": "diff --git a/lib/rucio/core/did_meta_plugins/json_meta.py b/lib/rucio/core/did_meta_plugins/json_meta.py\n--- a/lib/rucio/core/did_meta_plugins/json_meta.py\n+++ b/lib/rucio/core/did_meta_plugins/json_meta.py\n@@ -30,6 +30,7 @@\n # - Brandon White, <bjwhite@fnal.gov>, 2019\n # - Aristeidis Fkiaras <aristeidis.fkiaras@cern.ch>, 2020\n # - Benedikt Ziemons <benedikt.ziemons@cern.ch>, 2020-2021\n+# - Rizart Dona <rizart.dona@cern.ch>, 2021\n \n import json as json_lib\n \n@@ -160,7 +161,7 @@\n         filters.pop('name', None)\n         for k, v in iteritems(filters):\n             if session.bind.dialect.name == 'oracle':\n-                query = query.filter(text(\"json_exists(meta,'$.%s?(@==''%s'')')\" % (k, v)))\n+                query = query.filter(text(\"json_exists(meta,'$?(@.{} == \\\"{}\\\")')\".format(k, v)))\n             else:\n                 query = query.filter(cast(models.DidMeta.meta[k], String) == type_coerce(v, JSON))\n", "issue": "list-dids-extended with new metadata plugin currently fails\nMotivation\r\n----------\r\n```\r\nrucio set-metadata --did\r\nCTA_LAPP_FREDERIC:cta_data_DL0_ObsId2021_02_22_15_49_11_975413919_TelId0.h\r\ndf5 --key ObsID --value 1\r\n\r\nrucio get-metadata\r\nCTA_LAPP_FREDERIC:cta_data_DL0_ObsId2021_02_22_15_49_11_975413919_TelId0.h\r\ndf5 --plugin ALL\r\nbsID:           1\r\naccess_cnt:      None\r\naccessed_at:     None\r\n....\r\n\r\nrucio list-dids-extended --filter ObsID=1 CTA_LAPP_FREDERIC:*\r\n/usr/lib/python2.7/site-packages/paramiko/transport.py:33:\r\nCryptographyDeprecationWarning: Python 2 is no longer supported by the\r\nPython core team. Support for it is now deprecated in cryptography, and\r\nwill be removed in a future release.\r\n  from cryptography.hazmat.backends import default_backend\r\n2021-02-22 15:58:35,693 ERROR   An unknown exception occurred.\r\nDetails: no error information passed (http status code: 500\r\n('internal_server_error', 'server_error', '/o\\\\', '\\xe2\\x9c\\x97'))\r\n```\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright 2013-2021 CERN\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# Authors:\n# - Vincent Garonne <vgaronne@gmail.com>, 2013-2018\n# - Martin Barisits <martin.barisits@cern.ch>, 2013-2019\n# - Cedric Serfon <cedric.serfon@cern.ch>, 2013-2020\n# - Ralph Vigne <ralph.vigne@cern.ch>, 2013\n# - Mario Lassnig <mario.lassnig@cern.ch>, 2013-2019\n# - Yun-Pin Sun <winter0128@gmail.com>, 2013\n# - Thomas Beermann <thomas.beermann@cern.ch>, 2013-2018\n# - Joaquin Bogado <jbogado@linti.unlp.edu.ar>, 2014-2015\n# - Wen Guan <wguan.icedew@gmail.com>, 2015\n# - Hannes Hansen <hannes.jakob.hansen@cern.ch>, 2018-2019\n# - Tobias Wegner <twegner@cern.ch>, 2019\n# - Andrew Lister <andrew.lister@stfc.ac.uk>, 2019\n# - Ruturaj Gujar, <ruturaj.gujar23@gmail.com>, 2019\n# - Brandon White, <bjwhite@fnal.gov>, 2019\n# - Aristeidis Fkiaras <aristeidis.fkiaras@cern.ch>, 2020\n# - Benedikt Ziemons <benedikt.ziemons@cern.ch>, 2020-2021\n\nimport json as json_lib\n\nfrom six import iteritems\nfrom sqlalchemy import String, cast, type_coerce, JSON\nfrom sqlalchemy.orm.exc import NoResultFound\nfrom sqlalchemy.sql.expression import text\n\nfrom rucio.common import exception\nfrom rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin\nfrom rucio.db.sqla import models\nfrom rucio.db.sqla.session import read_session, transactional_session, stream_session\nfrom rucio.db.sqla.util import json_implemented\n\n\nclass JSONDidMeta(DidMetaPlugin):\n    \"\"\"\n    A plugin to store DID metadata on a table on the relational database, using JSON blobs\n    \"\"\"\n\n    def __init__(self):\n        super(JSONDidMeta, self).__init__()\n        self.plugin_name = \"JSON\"\n\n    @read_session\n    def get_metadata(self, scope, name, session=None):\n        \"\"\"\n        Get data identifier metadata (JSON)\n\n        :param scope: The scope name.\n        :param name: The data identifier name.\n        :param session: The database session in use.\n        \"\"\"\n        if not json_implemented(session=session):\n            raise NotImplementedError\n\n        try:\n            row = session.query(models.DidMeta).filter_by(scope=scope, name=name).one()\n            meta = getattr(row, 'meta')\n            return json_lib.loads(meta) if session.bind.dialect.name in ['oracle', 'sqlite'] else meta\n        except NoResultFound:\n            raise exception.DataIdentifierNotFound(\"No generic metadata found for '%(scope)s:%(name)s'\" % locals())\n\n    def set_metadata(self, scope, name, key, value, recursive=False, session=None):\n        self.set_metadata_bulk(scope=scope, name=name, meta={key: value}, recursive=recursive, session=session)\n\n    @transactional_session\n    def set_metadata_bulk(self, scope, name, meta, recursive=False, session=None):\n        if not json_implemented(session=session):\n            raise NotImplementedError\n\n        if session.query(models.DataIdentifier).filter_by(scope=scope, name=name).one_or_none() is None:\n            raise exception.DataIdentifierNotFound(\"Data identifier '%s:%s' not found\" % (scope, name))\n\n        row_did_meta = session.query(models.DidMeta).filter_by(scope=scope, name=name).scalar()\n        if row_did_meta is None:\n            # Add metadata column to new table (if not already present)\n            row_did_meta = models.DidMeta(scope=scope, name=name)\n            row_did_meta.save(session=session, flush=False)\n\n        existing_meta = {}\n        if hasattr(row_did_meta, 'meta'):\n            if row_did_meta.meta:\n                existing_meta = row_did_meta.meta\n\n        # Oracle returns a string instead of a dict\n        if session.bind.dialect.name in ['oracle', 'sqlite'] and existing_meta:\n            existing_meta = json_lib.loads(existing_meta)\n\n        for key, value in meta.items():\n            existing_meta[key] = value\n\n        row_did_meta.meta = None\n        session.flush()\n\n        # Oracle insert takes a string as input\n        if session.bind.dialect.name in ['oracle', 'sqlite']:\n            existing_meta = json_lib.dumps(existing_meta)\n\n        row_did_meta.meta = existing_meta\n        row_did_meta.save(session=session, flush=True)\n\n    @transactional_session\n    def delete_metadata(self, scope, name, key, session=None):\n        \"\"\"\n        Delete a key from the metadata column\n\n        :param scope: the scope of did\n        :param name: the name of the did\n        :param key: the key to be deleted\n        \"\"\"\n        if not json_implemented(session=session):\n            raise NotImplementedError\n\n        try:\n            row = session.query(models.DidMeta).filter_by(scope=scope, name=name).one()\n            existing_meta = getattr(row, 'meta')\n            # Oracle returns a string instead of a dict\n            if session.bind.dialect.name in ['oracle', 'sqlite'] and existing_meta is not None:\n                existing_meta = json_lib.loads(existing_meta)\n\n            if key not in existing_meta:\n                raise exception.KeyNotFound(key)\n\n            existing_meta.pop(key, None)\n\n            row.meta = None\n            session.flush()\n\n            # Oracle insert takes a string as input\n            if session.bind.dialect.name in ['oracle', 'sqlite']:\n                existing_meta = json_lib.dumps(existing_meta)\n\n            row.meta = existing_meta\n        except NoResultFound:\n            raise exception.DataIdentifierNotFound(\"Key not found for data identifier '%(scope)s:%(name)s'\" % locals())\n\n    @stream_session\n    def list_dids(self, scope, filters, type='collection', ignore_case=False, limit=None,\n                  offset=None, long=False, recursive=False, session=None):\n        # Currently for sqlite only add, get and delete is implemented.\n        if not json_implemented(session=session):\n            raise NotImplementedError\n\n        query = session.query(models.DidMeta)\n        if scope is not None:\n            query = query.filter(models.DidMeta.scope == scope)\n        filters.pop('name', None)\n        for k, v in iteritems(filters):\n            if session.bind.dialect.name == 'oracle':\n                query = query.filter(text(\"json_exists(meta,'$.%s?(@==''%s'')')\" % (k, v)))\n            else:\n                query = query.filter(cast(models.DidMeta.meta[k], String) == type_coerce(v, JSON))\n\n        if long:\n            for row in query.yield_per(5):\n                yield {\n                    'scope': row.scope,\n                    'name': row.name,\n                    'did_type': 'Info not available in JSON Plugin',\n                    'bytes': 'Info not available in JSON Plugin',\n                    'length': 'Info not available in JSON Plugin'\n                }\n        else:\n            for row in query.yield_per(5):\n                yield row.name\n\n    @read_session\n    def manages_key(self, key, session=None):\n        return json_implemented(session=session)\n\n    def get_plugin_name(self):\n        \"\"\"\n        Returns Plugins Name.\n        This can then be used when listing the metadata of did to only provide dids from this plugin.\n        \"\"\"\n        return self.plugin_name\n", "path": "lib/rucio/core/did_meta_plugins/json_meta.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright 2013-2021 CERN\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# Authors:\n# - Vincent Garonne <vgaronne@gmail.com>, 2013-2018\n# - Martin Barisits <martin.barisits@cern.ch>, 2013-2019\n# - Cedric Serfon <cedric.serfon@cern.ch>, 2013-2020\n# - Ralph Vigne <ralph.vigne@cern.ch>, 2013\n# - Mario Lassnig <mario.lassnig@cern.ch>, 2013-2019\n# - Yun-Pin Sun <winter0128@gmail.com>, 2013\n# - Thomas Beermann <thomas.beermann@cern.ch>, 2013-2018\n# - Joaquin Bogado <jbogado@linti.unlp.edu.ar>, 2014-2015\n# - Wen Guan <wguan.icedew@gmail.com>, 2015\n# - Hannes Hansen <hannes.jakob.hansen@cern.ch>, 2018-2019\n# - Tobias Wegner <twegner@cern.ch>, 2019\n# - Andrew Lister <andrew.lister@stfc.ac.uk>, 2019\n# - Ruturaj Gujar, <ruturaj.gujar23@gmail.com>, 2019\n# - Brandon White, <bjwhite@fnal.gov>, 2019\n# - Aristeidis Fkiaras <aristeidis.fkiaras@cern.ch>, 2020\n# - Benedikt Ziemons <benedikt.ziemons@cern.ch>, 2020-2021\n# - Rizart Dona <rizart.dona@cern.ch>, 2021\n\nimport json as json_lib\n\nfrom six import iteritems\nfrom sqlalchemy import String, cast, type_coerce, JSON\nfrom sqlalchemy.orm.exc import NoResultFound\nfrom sqlalchemy.sql.expression import text\n\nfrom rucio.common import exception\nfrom rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin\nfrom rucio.db.sqla import models\nfrom rucio.db.sqla.session import read_session, transactional_session, stream_session\nfrom rucio.db.sqla.util import json_implemented\n\n\nclass JSONDidMeta(DidMetaPlugin):\n    \"\"\"\n    A plugin to store DID metadata on a table on the relational database, using JSON blobs\n    \"\"\"\n\n    def __init__(self):\n        super(JSONDidMeta, self).__init__()\n        self.plugin_name = \"JSON\"\n\n    @read_session\n    def get_metadata(self, scope, name, session=None):\n        \"\"\"\n        Get data identifier metadata (JSON)\n\n        :param scope: The scope name.\n        :param name: The data identifier name.\n        :param session: The database session in use.\n        \"\"\"\n        if not json_implemented(session=session):\n            raise NotImplementedError\n\n        try:\n            row = session.query(models.DidMeta).filter_by(scope=scope, name=name).one()\n            meta = getattr(row, 'meta')\n            return json_lib.loads(meta) if session.bind.dialect.name in ['oracle', 'sqlite'] else meta\n        except NoResultFound:\n            raise exception.DataIdentifierNotFound(\"No generic metadata found for '%(scope)s:%(name)s'\" % locals())\n\n    def set_metadata(self, scope, name, key, value, recursive=False, session=None):\n        self.set_metadata_bulk(scope=scope, name=name, meta={key: value}, recursive=recursive, session=session)\n\n    @transactional_session\n    def set_metadata_bulk(self, scope, name, meta, recursive=False, session=None):\n        if not json_implemented(session=session):\n            raise NotImplementedError\n\n        if session.query(models.DataIdentifier).filter_by(scope=scope, name=name).one_or_none() is None:\n            raise exception.DataIdentifierNotFound(\"Data identifier '%s:%s' not found\" % (scope, name))\n\n        row_did_meta = session.query(models.DidMeta).filter_by(scope=scope, name=name).scalar()\n        if row_did_meta is None:\n            # Add metadata column to new table (if not already present)\n            row_did_meta = models.DidMeta(scope=scope, name=name)\n            row_did_meta.save(session=session, flush=False)\n\n        existing_meta = {}\n        if hasattr(row_did_meta, 'meta'):\n            if row_did_meta.meta:\n                existing_meta = row_did_meta.meta\n\n        # Oracle returns a string instead of a dict\n        if session.bind.dialect.name in ['oracle', 'sqlite'] and existing_meta:\n            existing_meta = json_lib.loads(existing_meta)\n\n        for key, value in meta.items():\n            existing_meta[key] = value\n\n        row_did_meta.meta = None\n        session.flush()\n\n        # Oracle insert takes a string as input\n        if session.bind.dialect.name in ['oracle', 'sqlite']:\n            existing_meta = json_lib.dumps(existing_meta)\n\n        row_did_meta.meta = existing_meta\n        row_did_meta.save(session=session, flush=True)\n\n    @transactional_session\n    def delete_metadata(self, scope, name, key, session=None):\n        \"\"\"\n        Delete a key from the metadata column\n\n        :param scope: the scope of did\n        :param name: the name of the did\n        :param key: the key to be deleted\n        \"\"\"\n        if not json_implemented(session=session):\n            raise NotImplementedError\n\n        try:\n            row = session.query(models.DidMeta).filter_by(scope=scope, name=name).one()\n            existing_meta = getattr(row, 'meta')\n            # Oracle returns a string instead of a dict\n            if session.bind.dialect.name in ['oracle', 'sqlite'] and existing_meta is not None:\n                existing_meta = json_lib.loads(existing_meta)\n\n            if key not in existing_meta:\n                raise exception.KeyNotFound(key)\n\n            existing_meta.pop(key, None)\n\n            row.meta = None\n            session.flush()\n\n            # Oracle insert takes a string as input\n            if session.bind.dialect.name in ['oracle', 'sqlite']:\n                existing_meta = json_lib.dumps(existing_meta)\n\n            row.meta = existing_meta\n        except NoResultFound:\n            raise exception.DataIdentifierNotFound(\"Key not found for data identifier '%(scope)s:%(name)s'\" % locals())\n\n    @stream_session\n    def list_dids(self, scope, filters, type='collection', ignore_case=False, limit=None,\n                  offset=None, long=False, recursive=False, session=None):\n        # Currently for sqlite only add, get and delete is implemented.\n        if not json_implemented(session=session):\n            raise NotImplementedError\n\n        query = session.query(models.DidMeta)\n        if scope is not None:\n            query = query.filter(models.DidMeta.scope == scope)\n        filters.pop('name', None)\n        for k, v in iteritems(filters):\n            if session.bind.dialect.name == 'oracle':\n                query = query.filter(text(\"json_exists(meta,'$?(@.{} == \\\"{}\\\")')\".format(k, v)))\n            else:\n                query = query.filter(cast(models.DidMeta.meta[k], String) == type_coerce(v, JSON))\n\n        if long:\n            for row in query.yield_per(5):\n                yield {\n                    'scope': row.scope,\n                    'name': row.name,\n                    'did_type': 'Info not available in JSON Plugin',\n                    'bytes': 'Info not available in JSON Plugin',\n                    'length': 'Info not available in JSON Plugin'\n                }\n        else:\n            for row in query.yield_per(5):\n                yield row.name\n\n    @read_session\n    def manages_key(self, key, session=None):\n        return json_implemented(session=session)\n\n    def get_plugin_name(self):\n        \"\"\"\n        Returns Plugins Name.\n        This can then be used when listing the metadata of did to only provide dids from this plugin.\n        \"\"\"\n        return self.plugin_name\n", "path": "lib/rucio/core/did_meta_plugins/json_meta.py"}]}