Commit 660f9050 by Don Mitchell

Merge pull request #3658 from edx/opaque-keys-location-to-son

Opaque keys location to son
parents ae99a170 46a976d7
...@@ -10,7 +10,7 @@ class Content: ...@@ -10,7 +10,7 @@ class Content:
self.content = content self.content = content
def get_id(self): def get_id(self):
return StaticContent.get_id_from_location(self.location) return self.location.to_deprecated_son()
class CachingTestCase(TestCase): class CachingTestCase(TestCase):
......
import bson.son
import re import re
XASSET_LOCATION_TAG = 'c4x' XASSET_LOCATION_TAG = 'c4x'
XASSET_SRCREF_PREFIX = 'xasset:' XASSET_SRCREF_PREFIX = 'xasset:'
...@@ -60,7 +59,7 @@ class StaticContent(object): ...@@ -60,7 +59,7 @@ class StaticContent(object):
) )
def get_id(self): def get_id(self):
return StaticContent.get_id_from_location(self.location) return self.location.to_deprecated_son(tag=XASSET_LOCATION_TAG)
def get_url_path(self): def get_url_path(self):
return self.location.to_deprecated_string() return self.location.to_deprecated_string()
...@@ -107,17 +106,6 @@ class StaticContent(object): ...@@ -107,17 +106,6 @@ class StaticContent(object):
return course_key.make_asset_key('asset', '').to_deprecated_string() return course_key.make_asset_key('asset', '').to_deprecated_string()
@staticmethod @staticmethod
def get_id_from_location(location):
"""
Get the doc store's primary key repr for this location
"""
return bson.son.SON([
('tag', 'c4x'), ('org', location.org), ('course', location.course),
('category', location.category), ('name', location.name),
('revision', location.revision),
])
@staticmethod
def get_location_from_path(path): def get_location_from_path(path):
""" """
Generate an AssetKey for the given path (old c4x/org/course/asset/name syntax) Generate an AssetKey for the given path (old c4x/org/course/asset/name syntax)
......
...@@ -2,7 +2,7 @@ import pymongo ...@@ -2,7 +2,7 @@ import pymongo
import gridfs import gridfs
from gridfs.errors import NoFile from gridfs.errors import NoFile
from xmodule.modulestore.mongo.base import location_to_query, MongoModuleStore, location_to_son from xmodule.modulestore.mongo.base import location_to_query, MongoModuleStore
from xmodule.contentstore.content import XASSET_LOCATION_TAG from xmodule.contentstore.content import XASSET_LOCATION_TAG
import logging import logging
...@@ -69,9 +69,7 @@ class MongoContentStore(ContentStore): ...@@ -69,9 +69,7 @@ class MongoContentStore(ContentStore):
assert not self.fs.exists({"_id": content_id}) assert not self.fs.exists({"_id": content_id})
def find(self, location, throw_on_not_found=True, as_stream=False): def find(self, location, throw_on_not_found=True, as_stream=False):
content_id = StaticContent.get_id_from_location(location) content_id = self.asset_db_key(location)
# Use slow attr based lookup b/c we weren't careful to control the key order in _id before
content_id = {u'_id.{}'.format(key): value for key, value in content_id.iteritems()}
fs_pointer = self.fs_files.find_one(content_id, fields={'_id': 1}) fs_pointer = self.fs_files.find_one(content_id, fields={'_id': 1})
if fs_pointer is None: if fs_pointer is None:
if throw_on_not_found: if throw_on_not_found:
...@@ -110,9 +108,7 @@ class MongoContentStore(ContentStore): ...@@ -110,9 +108,7 @@ class MongoContentStore(ContentStore):
return None return None
def get_stream(self, location): def get_stream(self, location):
content_id = StaticContent.get_id_from_location(location) content_id = self.asset_db_key(location)
# use slow attr based lookup because we weren't careful to control the key order in _id before
content_id = {u'_id.{}'.format(key): value for key, value in content_id.iteritems()}
fs_pointer = self.fs_files.find_one(content_id, fields={'_id': 1}) fs_pointer = self.fs_files.find_one(content_id, fields={'_id': 1})
try: try:
...@@ -247,8 +243,10 @@ class MongoContentStore(ContentStore): ...@@ -247,8 +243,10 @@ class MongoContentStore(ContentStore):
for attr in attr_dict.iterkeys(): for attr in attr_dict.iterkeys():
if attr in ['_id', 'md5', 'uploadDate', 'length']: if attr in ['_id', 'md5', 'uploadDate', 'length']:
raise AttributeError("{} is a protected attribute.".format(attr)) raise AttributeError("{} is a protected attribute.".format(attr))
asset_db_key = {'_id': location_to_son(location, tag=XASSET_LOCATION_TAG)} asset_db_key = self.asset_db_key(location)
if self.fs_files.find(asset_db_key).count() == 0: # FIXME remove fetch and use a form of update which fails if doesn't exist
item = self.fs_files.find_one(asset_db_key)
if item is None:
raise NotFoundError(asset_db_key) raise NotFoundError(asset_db_key)
self.fs_files.update(asset_db_key, {"$set": attr_dict}) self.fs_files.update(asset_db_key, {"$set": attr_dict})
...@@ -262,9 +260,10 @@ class MongoContentStore(ContentStore): ...@@ -262,9 +260,10 @@ class MongoContentStore(ContentStore):
:param location: a c4x asset location :param location: a c4x asset location
""" """
item = self.fs_files.find_one({'_id': location_to_son(location, tag=XASSET_LOCATION_TAG)}) asset_db_key = self.asset_db_key(location)
item = self.fs_files.find_one(asset_db_key)
if item is None: if item is None:
raise NotFoundError() raise NotFoundError(asset_db_key)
return item return item
def delete_all_course_assets(self, course_key): def delete_all_course_assets(self, course_key):
...@@ -277,3 +276,10 @@ class MongoContentStore(ContentStore): ...@@ -277,3 +276,10 @@ class MongoContentStore(ContentStore):
matching_assets = self.fs_files.find(course_query) matching_assets = self.fs_files.find(course_query)
for asset in matching_assets: for asset in matching_assets:
self.fs.delete(asset['_id']) self.fs.delete(asset['_id'])
@staticmethod
def asset_db_key(location):
"""
Returns the database query to find the given asset location.
"""
return location.to_deprecated_son(tag=XASSET_LOCATION_TAG, prefix='_id.')
...@@ -10,7 +10,6 @@ import re ...@@ -10,7 +10,6 @@ import re
from django.conf import settings from django.conf import settings
from django.core.cache import get_cache, InvalidCacheBackendError from django.core.cache import get_cache, InvalidCacheBackendError
from django.dispatch import Signal
import django.utils import django.utils
from xmodule.modulestore.loc_mapper_store import LocMapperStore from xmodule.modulestore.loc_mapper_store import LocMapperStore
......
...@@ -248,29 +248,17 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -248,29 +248,17 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
return jsonfields return jsonfields
def location_to_son(location, prefix='', tag='i4x'):
"""
Converts a location into a SON object with the same key order
"""
son = SON({prefix + 'tag': tag})
for field_name in location.KEY_FIELDS:
# Filter the run, because the existing data doesn't have it stored
if field_name != 'run':
son[prefix + field_name] = getattr(location, field_name)
return son
# The only thing using this w/ wildcards is contentstore.mongo for asset retrieval # The only thing using this w/ wildcards is contentstore.mongo for asset retrieval
def location_to_query(location, wildcard=True, tag='i4x'): def location_to_query(location, wildcard=True, tag='i4x'):
""" """
Takes a Location and returns a SON object that will query for that location by subfields Takes a Location and returns a SON object that will query for that location by subfields
rather than subdoc. Note: location_to_son is faster in mongo as it does subdoc equivalence. rather than subdoc.
Fields in location that are None are ignored in the query Fields in location that are None are ignored in the query.
If `wildcard` is True, then a None in a location is treated as a wildcard If `wildcard` is True, then a None in a location is treated as a wildcard
query. Otherwise, it is searched for literally query. Otherwise, it is searched for literally
""" """
query = location_to_son(location, prefix='_id.', tag=tag) query = location.to_deprecated_son(prefix='_id.', tag=tag)
if wildcard: if wildcard:
for key, value in query.items(): for key, value in query.items():
...@@ -481,7 +469,7 @@ class MongoModuleStore(ModuleStoreWriteBase): ...@@ -481,7 +469,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
# first get non-draft in a round-trip # first get non-draft in a round-trip
query = { query = {
'_id': {'$in': [ '_id': {'$in': [
location_to_son(course_key.make_usage_key_from_deprecated_string(item)) for item in items course_key.make_usage_key_from_deprecated_string(item).to_deprecated_son() for item in items
]} ]}
} }
return list(self.collection.find(query)) return list(self.collection.find(query))
...@@ -601,7 +589,7 @@ class MongoModuleStore(ModuleStoreWriteBase): ...@@ -601,7 +589,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
''' '''
assert isinstance(location, Location) assert isinstance(location, Location)
item = self.collection.find_one( item = self.collection.find_one(
{'_id': location_to_son(location)}, {'_id': location.to_deprecated_son()},
sort=[('revision', pymongo.ASCENDING)], sort=[('revision', pymongo.ASCENDING)],
) )
if item is None: if item is None:
...@@ -886,7 +874,7 @@ class MongoModuleStore(ModuleStoreWriteBase): ...@@ -886,7 +874,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
# See http://www.mongodb.org/display/DOCS/Updating for # See http://www.mongodb.org/display/DOCS/Updating for
# atomic update syntax # atomic update syntax
result = self.collection.update( result = self.collection.update(
{'_id': location_to_son(location)}, {'_id': location.to_deprecated_son()},
{'$set': update}, {'$set': update},
multi=False, multi=False,
upsert=True, upsert=True,
...@@ -975,7 +963,7 @@ class MongoModuleStore(ModuleStoreWriteBase): ...@@ -975,7 +963,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
# Must include this to avoid the django debug toolbar (which defines the deprecated "safe=False") # Must include this to avoid the django debug toolbar (which defines the deprecated "safe=False")
# from overriding our default value set in the init method. # from overriding our default value set in the init method.
self.collection.remove({'_id': location_to_son(location)}, safe=self.collection.safe) self.collection.remove({'_id': location.to_deprecated_son()}, safe=self.collection.safe)
# recompute (and update) the metadata inheritance tree which is cached # recompute (and update) the metadata inheritance tree which is cached
self.refresh_cached_metadata_inheritance_tree(location.course_key) self.refresh_cached_metadata_inheritance_tree(location.course_key)
......
...@@ -66,7 +66,7 @@ def _clear_assets(location): ...@@ -66,7 +66,7 @@ def _clear_assets(location):
for asset in assets: for asset in assets:
asset_location = AssetLocation._from_deprecated_son(asset["_id"], location.course_key.run) asset_location = AssetLocation._from_deprecated_son(asset["_id"], location.course_key.run)
del_cached_content(asset_location) del_cached_content(asset_location)
mongo_id = StaticContent.get_id_from_location(asset_location) mongo_id = asset_location.to_deprecated_son()
store.delete(mongo_id) store.delete(mongo_id)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment