Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Universal message storage core implementation #997

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Core/XMPPFramework.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#import "XMPPTimer.h"
#import "XMPPCoreDataStorage.h"
#import "XMPPCoreDataStorageProtected.h"
#import "NSManagedObject+XMPPCoreDataStorage.h"
#import "NSXMLElement+XEP_0203.h"
#import "XMPPFileTransfer.h"
#import "XMPPIncomingFileTransfer.h"
Expand Down Expand Up @@ -163,7 +164,14 @@
#import "XMPPRoomLightCoreDataStorage.h"
#import "XMPPRoomLightCoreDataStorageProtected.h"
#import "XMPPRoomLightMessageCoreDataStorageObject.h"

#import "XMPPMessageCoreDataStorage.h"
#import "XMPPMessageCoreDataStorageObject.h"
#import "XMPPMessageCoreDataStorageObject+Protected.h"
#import "XMPPMessageCoreDataStorageObject+ContextHelpers.h"
#import "XMPPMessageContextCoreDataStorageObject.h"
#import "XMPPMessageContextCoreDataStorageObject+Protected.h"
#import "XMPPMessageContextItemCoreDataStorageObject.h"
#import "XMPPMessageContextItemCoreDataStorageObject+Protected.h"

FOUNDATION_EXPORT double XMPPFrameworkVersionNumber;
FOUNDATION_EXPORT const unsigned char XMPPFrameworkVersionString[];
33 changes: 33 additions & 0 deletions Extensions/CoreDataStorage/NSManagedObject+XMPPCoreDataStorage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#import <CoreData/CoreData.h>
#import "XMPPJID.h"

NS_ASSUME_NONNULL_BEGIN

@interface NSManagedObject (XMPPCoreDataStorage)

/// @brief Inserts a managed object with an entity whose name matches the class name.
/// @discussion An assertion will be triggered if no matching entity is found in the model.
+ (instancetype)xmpp_insertNewObjectInManagedObjectContext:(NSManagedObjectContext *)managedObjectContext;

/// @brief Returns a fetch request for an entity whose name matches the class name.
/// @discussion An assertion will be triggered if no matching entity is found in the model.
+ (NSFetchRequest *)xmpp_fetchRequestInManagedObjectContext:(NSManagedObjectContext *)managedObjectContext;

/// @brief Returns a predicate for filtering managed objects on JID component attributes.
/// @discussion The provided keypaths are relative to the fetched entity and the filtering logic follows @c [XMPPJID @c isEqualToJID:options:] implementation.
+ (NSPredicate *)xmpp_jidPredicateWithDomainKeyPath:(NSString *)domainKeyPath
resourceKeyPath:(NSString *)resourceKeyPath
userKeyPath:(NSString *)userKeyPath
value:(XMPPJID *)value
compareOptions:(XMPPJIDCompareOptions)compareOptions;

@end

@interface NSManagedObjectContext (XMPPCoreDataStorage)

/// Executes the provided fetch request raising an assertion upon failure.
- (NSArray *)xmpp_executeForcedSuccessFetchRequest:(NSFetchRequest *)fetchRequest;

@end

NS_ASSUME_NONNULL_END
65 changes: 65 additions & 0 deletions Extensions/CoreDataStorage/NSManagedObject+XMPPCoreDataStorage.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#import "NSManagedObject+XMPPCoreDataStorage.h"

@implementation NSManagedObject (XMPPCoreDataStorage)

+ (instancetype)xmpp_insertNewObjectInManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
return [[self alloc] initWithEntity:[self xmpp_entityInManagedObjectContext:managedObjectContext]
insertIntoManagedObjectContext:managedObjectContext];
}

+ (NSFetchRequest *)xmpp_fetchRequestInManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest.entity = [self xmpp_entityInManagedObjectContext:managedObjectContext];
return fetchRequest;
}

+ (NSPredicate *)xmpp_jidPredicateWithDomainKeyPath:(NSString *)domainKeyPath resourceKeyPath:(NSString *)resourceKeyPath userKeyPath:(NSString *)userKeyPath value:(XMPPJID *)value compareOptions:(XMPPJIDCompareOptions)compareOptions
{
NSMutableArray *subpredicates = [[NSMutableArray alloc] init];

if (compareOptions & XMPPJIDCompareDomain) {
[subpredicates addObject:[NSPredicate predicateWithFormat:@"%K = %@", domainKeyPath, value.domain]];
}

if (compareOptions & XMPPJIDCompareResource) {
[subpredicates addObject:[NSPredicate predicateWithFormat:@"%K = %@", resourceKeyPath, value.resource]];
}

if (compareOptions & XMPPJIDCompareUser) {
[subpredicates addObject:[NSPredicate predicateWithFormat:@"%K = %@", userKeyPath, value.user]];
}

return [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
}

+ (NSEntityDescription *)xmpp_entityInManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
NSUInteger selfEntityIndex = [managedObjectContext.persistentStoreCoordinator.managedObjectModel.entities indexOfObjectPassingTest:^BOOL(NSEntityDescription * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
BOOL matchesSelf = [obj.managedObjectClassName isEqualToString:NSStringFromClass(self)];
if (matchesSelf) {
*stop = YES;
}
return matchesSelf;
}];
NSAssert(selfEntityIndex != NSNotFound, @"Entity for %@ not found", self);

return managedObjectContext.persistentStoreCoordinator.managedObjectModel.entities[selfEntityIndex];
}

@end

@implementation NSManagedObjectContext (XMPPCoreDataStorage)

- (NSArray *)xmpp_executeForcedSuccessFetchRequest:(NSFetchRequest *)fetchRequest
{
NSError *error;
NSArray *fetchResult = [self executeFetchRequest:fetchRequest error:&error];
if (!fetchResult) {
NSAssert(NO, @"Fetch request %@ failed with error %@", fetchRequest, error);
}
return fetchResult;
}

@end
2 changes: 1 addition & 1 deletion Extensions/CoreDataStorage/XMPPCoreDataStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
return;
}
XMPPLogVerbose(@"%@: Creating persistentStoreCoordinator", [self class]);

persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#import "XMPPMessageContextCoreDataStorageObject.h"

NS_ASSUME_NONNULL_BEGIN

@class XMPPMessageCoreDataStorageObject, XMPPMessageContextJIDItemCoreDataStorageObject, XMPPMessageContextMarkerItemCoreDataStorageObject, XMPPMessageContextStringItemCoreDataStorageObject, XMPPMessageContextTimestampItemCoreDataStorageObject;

@interface XMPPMessageContextCoreDataStorageObject (Protected)

/// The message the context object is assigned to.
@property (nonatomic, strong, nullable) XMPPMessageCoreDataStorageObject *message;

/// The JID values aggregated by the context object.
@property (nonatomic, copy, nullable) NSSet<XMPPMessageContextJIDItemCoreDataStorageObject *> *jidItems;

/// The markers aggregated by the context object.
@property (nonatomic, copy, nullable) NSSet<XMPPMessageContextMarkerItemCoreDataStorageObject *> *markerItems;

/// The string values aggregated by the context object.
@property (nonatomic, copy, nullable) NSSet<XMPPMessageContextStringItemCoreDataStorageObject *> *stringItems;

/// The timestamp values aggregated by the context object.
@property (nonatomic, copy, nullable) NSSet<XMPPMessageContextTimestampItemCoreDataStorageObject *> *timestampItems;

@end

@interface XMPPMessageContextCoreDataStorageObject (CoreDataGeneratedRelationshipAccesssors)

- (void)addJidItemsObject:(XMPPMessageContextJIDItemCoreDataStorageObject *)value;
- (void)removeJidItemsObject:(XMPPMessageContextJIDItemCoreDataStorageObject *)value;
- (void)addJidItems:(NSSet<XMPPMessageContextJIDItemCoreDataStorageObject *> *)value;
- (void)removeJidItems:(NSSet<XMPPMessageContextJIDItemCoreDataStorageObject *> *)value;

- (void)addMarkerItemsObject:(XMPPMessageContextMarkerItemCoreDataStorageObject *)value;
- (void)removeMarkerItemsObject:(XMPPMessageContextMarkerItemCoreDataStorageObject *)value;
- (void)addMarkerItems:(NSSet<XMPPMessageContextMarkerItemCoreDataStorageObject *> *)value;
- (void)removeMarkerItems:(NSSet<XMPPMessageContextMarkerItemCoreDataStorageObject *> *)value;

- (void)addStringItemsObject:(XMPPMessageContextStringItemCoreDataStorageObject *)value;
- (void)removeStringItemsObject:(XMPPMessageContextStringItemCoreDataStorageObject *)value;
- (void)addStringItems:(NSSet<XMPPMessageContextStringItemCoreDataStorageObject *> *)value;
- (void)removeStringItems:(NSSet<XMPPMessageContextStringItemCoreDataStorageObject *> *)value;

- (void)addTimestampItemsObject:(XMPPMessageContextTimestampItemCoreDataStorageObject *)value;
- (void)removeTimestampItemsObject:(XMPPMessageContextTimestampItemCoreDataStorageObject *)value;
- (void)addTimestampItems:(NSSet<XMPPMessageContextTimestampItemCoreDataStorageObject *> *)value;
- (void)removeTimestampItems:(NSSet<XMPPMessageContextTimestampItemCoreDataStorageObject *> *)value;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#import <CoreData/CoreData.h>

NS_ASSUME_NONNULL_BEGIN

/**
An auxiliary context storage object aggregating module-provided values assigned to a stored message.

@see XMPPMessageCoreDataStorageObject
@see XMPPMessageContextItemCoreDataStorageObject
*/
@interface XMPPMessageContextCoreDataStorageObject : NSManagedObject

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#import "XMPPMessageContextCoreDataStorageObject.h"
#import "XMPPMessageContextCoreDataStorageObject+Protected.h"

@interface XMPPMessageContextCoreDataStorageObject ()

@property (nonatomic, strong, nullable) XMPPMessageCoreDataStorageObject *message;
@property (nonatomic, copy, nullable) NSSet<XMPPMessageContextJIDItemCoreDataStorageObject *> *jidItems;
@property (nonatomic, copy, nullable) NSSet<XMPPMessageContextMarkerItemCoreDataStorageObject *> *markerItems;
@property (nonatomic, copy, nullable) NSSet<XMPPMessageContextStringItemCoreDataStorageObject *> *stringItems;
@property (nonatomic, copy, nullable) NSSet<XMPPMessageContextTimestampItemCoreDataStorageObject *> *timestampItems;

@end

@implementation XMPPMessageContextCoreDataStorageObject

@dynamic message, jidItems, markerItems, stringItems, timestampItems;

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#import "XMPPMessageContextItemCoreDataStorageObject.h"
#import "XMPPJID.h"

NS_ASSUME_NONNULL_BEGIN

@class XMPPMessageContextCoreDataStorageObject;

typedef NS_ENUM(int16_t, XMPPMessageDirection);

/// A tag assigned to a JID auxiliary value.
typedef NSString * XMPPMessageContextJIDItemTag NS_EXTENSIBLE_STRING_ENUM;

/// An tag assigned to an auxiliary marker.
typedef NSString * XMPPMessageContextMarkerItemTag NS_EXTENSIBLE_STRING_ENUM;

/// A tag assigned to a string auxiliary value.
typedef NSString * XMPPMessageContextStringItemTag NS_EXTENSIBLE_STRING_ENUM;

/// A tag assigned to a timestamp auxiliary value.
typedef NSString * XMPPMessageContextTimestampItemTag NS_EXTENSIBLE_STRING_ENUM;

@interface XMPPMessageContextItemCoreDataStorageObject (Protected)

/// The context element aggregating the value.
@property (nonatomic, strong, nullable) XMPPMessageContextCoreDataStorageObject *contextElement;

@end

/// A storage object representing a module-provided JID value assigned to a stored message.
@interface XMPPMessageContextJIDItemCoreDataStorageObject : XMPPMessageContextItemCoreDataStorageObject

/// The tag assigned to the value.
@property (nonatomic, copy, nullable) XMPPMessageContextJIDItemTag tag;

/// The stored JID value.
@property (nonatomic, strong, nullable) XMPPJID *value;

/// Returns a predicate to fetch values with the specified tag.
+ (NSPredicate *)tagPredicateWithValue:(XMPPMessageContextJIDItemTag)value;

/// Returns a predicate to fetch items with the specified value.
+ (NSPredicate *)jidPredicateWithValue:(XMPPJID *)value compareOptions:(XMPPJIDCompareOptions)compareOptions;

@end

/// A storage object representing a module-provided marker assigned to a stored message.
@interface XMPPMessageContextMarkerItemCoreDataStorageObject : XMPPMessageContextItemCoreDataStorageObject

/// The tag assigned to the marker.
@property (nonatomic, copy, nullable) XMPPMessageContextMarkerItemTag tag;

/// Returns a predicate to fetch markers with the specified tag.
+ (NSPredicate *)tagPredicateWithValue:(XMPPMessageContextMarkerItemTag)value;

@end

/// A storage object representing a module-provided string value assigned to a stored message.
@interface XMPPMessageContextStringItemCoreDataStorageObject : XMPPMessageContextItemCoreDataStorageObject

/// The tag assigned to the value.
@property (nonatomic, copy, nullable) XMPPMessageContextStringItemTag tag;

/// The stored string value.
@property (nonatomic, copy, nullable) NSString *value;

/// Returns a predicate to fetch values with the specified tag.
+ (NSPredicate *)tagPredicateWithValue:(XMPPMessageContextStringItemTag)tag;

/// Returns a predicate to fetch items with the specified value.
+ (NSPredicate *)stringPredicateWithValue:(NSString *)value;

@end

/// A storage object representing a module-provided timestamp value assigned to a stored message.
@interface XMPPMessageContextTimestampItemCoreDataStorageObject : XMPPMessageContextItemCoreDataStorageObject

/// The tag assigned to the value.
@property (nonatomic, copy, nullable) XMPPMessageContextTimestampItemTag tag;

/// The stored timestamp value.
@property (nonatomic, strong, nullable) NSDate *value;

/// Returns a predicate to fetch values with the specified tag.
+ (NSPredicate *)tagPredicateWithValue:(XMPPMessageContextTimestampItemTag)value;

/// Returns a predicate to fetch items with values in the specified range.
+ (NSPredicate *)timestampRangePredicateWithStartValue:(nullable NSDate *)startValue endValue:(nullable NSDate *)endValue;

@end

NS_ASSUME_NONNULL_END
Loading