Skip to content

Commit

Permalink
Add 'src/' from commit '34cdb31c791de486df59b436a5f80ed0de5fe291'
Browse files Browse the repository at this point in the history
git-subtree-dir: src
git-subtree-mainline: 8d75b90
git-subtree-split: 34cdb31
  • Loading branch information
adrianheine committed Jul 3, 2014
2 parents 8d75b90 + 34cdb31 commit 3e18ec1
Show file tree
Hide file tree
Showing 6 changed files with 461 additions and 0 deletions.
131 changes: 131 additions & 0 deletions src/serialization.EntityUnserializer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/**
* @licence GNU GPL v2+
* @author Daniel Werner < daniel.werner@wikimedia.de >
*/
( function( wb, util, $ ) {
'use strict';

var MODULE = wb.serialization,
PARENT = MODULE.Unserializer;

/**
* Unserializers for specific entity types.
* @type wb.serialization.Unserializer
*/
var typeSpecificUnserializers = {};

/**
* Helper for unserializing multilingual value.
*
* @param {Object} serialization
* @return {Object} Map with language codes as fields
*/
function unserializeMultilingualValue( serialization ) {
if( !serialization ) {
return {};
}
var unserialized = {};

for( var lang in serialization ) {
unserialized[ lang ] = serialization[ lang ].value;
}
return unserialized;
}

/**
* Helper for unserializing an Entity's claims.
*
* TODO: we should probably have a ClaimList which then has its own unserializer.
*
* @param {Object} serialization
* @return wb.Claim[]
*/
function unserializeClaims( serialization ) {
var claims = [];

// get claims:
for( var propId in serialization || {} ) {
var claimsPerProp = serialization[ propId ];

for( var i in claimsPerProp ) {
var serializedClaim = claimsPerProp[ i ],
// TODO: use ClaimUnserializer here after it got implemented
claim = wb.Claim.newFromJSON( serializedClaim );

claims.push( claim );
}
}
return claims;
}

/**
* Unserializer for Property entities.
*
* @constructor
* @extends wb.Unserializer
* @since 0.4
*/
var SELF = MODULE.EntityUnserializer = util.inherit( 'WbEntityUnserializer', PARENT, {
/**
* @see wb.serialization.Unserializer.unserialize
*
* @return wb.Entity
*/
unserialize: function( serialization ) {
var entityType = serialization.type,
typeSpecificUnserializer = typeSpecificUnserializers[ entityType ];

if( !entityType || typeof entityType !== 'string' ) {
throw new Error( 'Can not determine type of Entity from serialized object' );
}

// create map with data which is the same for all types of entities:
var entityMapData = {
type: entityType,
id: serialization.id,
title: serialization.title,
label: unserializeMultilingualValue( serialization.labels ),
description: unserializeMultilingualValue( serialization.descriptions ),
aliases: unserializeMultilingualValue( serialization.aliases ),
claims: unserializeClaims( serialization.claims )
};

// extend map with data which is specific to the entity type if there is handling for
// the entity type we are dealing with:
if( typeSpecificUnserializer ) {
typeSpecificUnserializer.setOptions( this._options );
var typeSpecificData = typeSpecificUnserializer.unserialize( serialization );

// merge type specific data with ordinary data
$.extend( entityMapData, typeSpecificData );
}

return wb.Entity.newFromMap(
entityMapData
);
}
} );

// register in SerializationFactory for wb.Entity unserialization handling:
MODULE.SerializerFactory.registerUnserializer( SELF, wb.Entity );

/**
* Allows to register advanced unserialization logic for a certain type of Entity. Takes the
* type the additional handling is required for and a Unserializer object which has the job to
* return the type specific map data as Object. The Object keys should contain the data which
* is different for the handled type of entity compared to other entity types. The keys should
* be what wb.Entity.newFromMap requires to create a new Entity of the specific type.
*
* @since 0.4
*
* @param {string} entityType
* @param {Function} TypeSpecificUnserializer Constructor which inherits from
* wb.serialization.Unserializer.
*/
SELF.registerTypeSpecificExpert = function( entityType, TypeSpecificUnserializer ) {
// for performance, we just create one instance of that unserializer and change its
// options whenever we will use it
typeSpecificUnserializers[ entityType ] = new TypeSpecificUnserializer();
};

}( wikibase, util, jQuery ) );
44 changes: 44 additions & 0 deletions src/serialization.EntityUnserializer.propertyExpert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* @licence GNU GPL v2+
* @author Daniel Werner < daniel.werner@wikimedia.de >
*/
( function( wb, util ) {
'use strict';

var MODULE = wb.serialization,
PARENT = MODULE.Unserializer;

/**
* Unserializer for parts of a Property Entity that are specific to Properties.
*
* @constructor
* @extends wb.Unserializer
* @since 0.4
*/
var PropertyUnserializationExpert =
util.inherit( 'WbEntityUnserializerPropertyExpert', PARENT,
{
/**
* @see wb.serialization.Unserializer.unserialize
*
* @return Object
*/
unserialize: function( serialization ) {
var dataTypeId = serialization.datatype;
if( !dataTypeId ) {
throw new Error( 'Property Entity unserializer expects a "datatype" field' );
}

return {
datatype: dataTypeId
};
}
} );

// register to EntityUnserializer:
MODULE.EntityUnserializer.registerTypeSpecificExpert(
wb.Property.TYPE,
PropertyUnserializationExpert
);

}( wikibase, util ) );
66 changes: 66 additions & 0 deletions src/serialization.Serializer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @licence GNU GPL v2+
* @author Daniel Werner < daniel.werner@wikimedia.de >
*/
( function( wb, util, $ ) {
'use strict';

var MODULE = wb.serialization;

/**
* Base for serializers.
*
* @param {Object} options
*
* @constructor
* @abstract
* @since 0.4
*/
var SELF = MODULE.Serializer = function WbSerializer( options ) {
if( options ) {
this.setOptions( options );
} else {
this._options = {};
}
};

$.extend( SELF.prototype, {
/**
* @type Object
*/
_options: null,

/**
* Returns the serialized form of some object.
*
* @since 0.4
*
* @param {Object} object
*/
serialize: util.abstractFunction,

/**
* Sets the serializer's options without just keeping a reference to the given object.
*
* @since 0.4
*
* @param options
*/
setOptions: function( options ) {
this._options = $.extend( {}, options );
},

/**
* Returns the serializer's options. Changing the returned object will have no affect on the
* serializer's actual options until they are set via setOptions.
*
* @since 0.4
*
* @return Object
*/
getOptions: function() {
return $.extend( {}, this._options );
}
} );

}( wikibase, util, jQuery ) );
140 changes: 140 additions & 0 deletions src/serialization.SerializerFactory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/**
* @licence GNU GPL v2+
* @author Daniel Werner < daniel.werner@wikimedia.de >
*/
( function( wb, $ ) {
'use strict';

var MODULE = wb.serialization;

/**
* Factory for creating serializers and unserializers suitable for certain objects, e.g. of the
* Wikibase data model.
*
* @constructor
* @since 0.4
*/
var SELF = MODULE.SerializerFactory = function SerializerFactory() {};

/**
* Array of arrays where the inner arrays holds two constructors. The first one the constructor
* a serializer's output should be the instance of and the second one the actual serializer.
* @type Array[]
*/
var serializers = [];

/**
* Array of arrays where the inner arrays holds two constructors. The first one the constructor
* a unserializer's output should be the instance of and the second one the actual unserializer.
* @type Array[]
*/
var unserializers = [];

/**
* Helper for building a new function for registering a factory member.
*
* @param {Array} store The factory's store.
* @param {Function} type Constructor newly registered factory members have to be instances of.
* @return Function
*/
function buildRegisterFn( store, type ) {
return function( FactoryMember, constructor ) {
if( !$.isFunction( constructor ) ) {
throw new Error( 'No constructor (function) given' );
}
if( !( ( new FactoryMember() ) instanceof type ) ) {
throw new Error( 'Given serializer is not an implementation of wb.serialization.Serializer' );
}

store.push( [
constructor,
FactoryMember
] );
};
}

/**
* Helper for building a new function for finding the right factory member and creating a new
* instance of it.
*
* @param {Array} store The factory's store.
* @param {string} storeSubject The subject of the store, used in error message descriptions.
* @return Function
*/
function buildLookupFn( store, storeSubject ) {
return function( constructor, options ) {
if( !$.isFunction( constructor ) ) {
throw new Error( 'No proper constructor has been provided for choosing a ' + storeSubject );
}

// find constructor matching the given one and create new instance of factory member
// responsible for handling instances of that given constructor:
for( var i in store ) {
if( store[i][0] === constructor ) {
return new store[i][1]( options );
}
}
throw new Error( 'No suitable ' + storeSubject + ' has been registered' );
};
}

$.extend( SELF.prototype, {
/**
* Returns a new serializer object suitable for a given object or for a given constructor's
* instances.
*
* @since 0.4
*
* @param {Object|Function} object
* @param {Object} options
* @return wb.serialization.Serializer
*/
newSerializerFor: ( function() {
// default lookup function as used by 'newUnserializerFor'
var lookupFn = buildLookupFn( unserializers, 'Unserializer' );

// build a function which will do the normal lookup but also allow for giving objects
// as first parameter. In that case we have to get the object's constructor.
return function( object, options ) {
if( !object ) {
throw new Error( 'Constructor or object expected' );
}
var constructorOfSerialized = $.isFunction( object ) ? object : object.constructor;
return lookupFn( constructorOfSerialized, options );
};
}() ),

/**
* Returns a new unserializer object suitable for unserializing some data into an instance
* of the given constructor.
*
* @since 0.4
*
* @param {Function} constructor
* @param {Object} options
* @return wb.serialization.Unserializer
*/
newUnserializerFor: buildLookupFn( unserializers, 'Unserializer' )
} );

/**
* Registers a serializer for objects of a certain given constructor.
*
* @since 0.4
*
* @param {wb.serialization.Serializer} serializer
* @param {Function} constructor
*/
SELF.registerSerializer = buildRegisterFn( serializers, MODULE.Serializer );

/**
* Registers a unserializer for objects of a certain given constructor.
*
* @since 0.4
*
* @param {wb.serialization.Unserializer} unserializer
* @param {Function} constructor
*/
SELF.registerUnserializer = buildRegisterFn( unserializers, MODULE.Unserializer );

}( wikibase, jQuery ) );
Loading

0 comments on commit 3e18ec1

Please sign in to comment.