OData Client for Objective-C(http://odataobjc.codeplex.com/)を触っていて気づいたことが、Azure Tableストレージを対象に日本語をパラメータとして検索するフィルタクエリを実行すると、Cocoaのライブラリ側で不正なURLという例外が発生してしまう。
なぜそんなことになっているかソースコードを見ていたら、ライブラリ内部ではフィルタクエリのURLエンコードを行っていないことがわかった。また、そのソースの近くにURLエンコードを試みたらしくコメントアウトされたコードがあるものの、それを外しても動かない。
原因をよくよく考えてみると、Azure Tableストレージに対するエンティティのクエリ構文では、全体をURLエンコードするのではなく個々のフィルタパラメータをURLエンコードしなくてはならないことがわかった。
例えば、
$filter=(PartitionKey eq 'あいうえお')
こんなクエリを投げたいときは
$filter=(PartitionKey%20eq%20%27%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A%27)
ではなく、
$filter=(PartitionKey%20eq%20'%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A')
のようにしなければならない(%20は+でもOK)。
しかし、このODataObjCではこの$filter=の後の文字列を直接メソッドのパラメータとして受け取るように作られているため、ライブラリ内部で対応するのは難しい感じです。(だから諦めたのかな。。。)
しかしこのままじゃ使えないため、$filter=の後の文字列を生成する簡単なクエリビルダを作成し、その中でURLエンコードするようにして対処してみました。というわけで作成したクエリビルダのソースを置いておきます。(URLエンコードの処理はODataObjCライブラリのUtilityクラスを利用してます)
Queries.h
#import <Foundation/Foundation.h>
#import "Utility.h"
@interface Queries : NSObject {
@private
NSString *filterString;
}
@property (nonatomic, retain) NSString *filterString;
- (id) initWithString:(NSString *)aFilterString;
+ (Queries *) withEmpty;
+ (Queries *) with:(NSString *)name eq:(NSString *)value;
+ (Queries *) with:(NSString *)name gt:(NSString *)value;
+ (Queries *) with:(NSString *)name ge:(NSString *)value;
+ (Queries *) with:(NSString *)name lt:(NSString *)value;
+ (Queries *) with:(NSString *)name le:(NSString *)value;
+ (Queries *) with:(NSString *)name ne:(NSString *)value;
- (Queries *) and:(Queries *)aQueries;
- (Queries *) or:(Queries *)aQueries;
- (Queries *) not;
@end
Queries.m
#import "Queries.h"
@implementation Queries
@synthesize filterString;
- (id) initWithString:(NSString *)aFilterString {
self.filterString = aFilterString;
return self;
}
+ (Queries *) withEmpty {
return [[[Queries alloc] initWithString:@""] autorelease];
}
+ (Queries *) with:(NSString *)name eq:(NSString *)value {
return [[[Queries alloc] initWithString:[NSString stringWithFormat:@"(%@ eq '%@')", name, [Utility URLEncode:value]]] autorelease];
}
+ (Queries *) with:(NSString *)name gt:(NSString *)value {
return [[[Queries alloc] initWithString:[NSString stringWithFormat:@"(%@ gt '%@')", name, [Utility URLEncode:value]]] autorelease];
}
+ (Queries *) with:(NSString *)name ge:(NSString *)value {
return [[[Queries alloc] initWithString:[NSString stringWithFormat:@"(%@ ge '%@')", name, [Utility URLEncode:value]]] autorelease];
}
+ (Queries *) with:(NSString *)name lt:(NSString *)value {
return [[[Queries alloc] initWithString:[NSString stringWithFormat:@"(%@ lt '%@')", name, [Utility URLEncode:value]]] autorelease];
}
+ (Queries *) with:(NSString *)name le:(NSString *)value {
return [[[Queries alloc] initWithString:[NSString stringWithFormat:@"(%@ le '%@')", name, [Utility URLEncode:value]]] autorelease];
}
+ (Queries *) with:(NSString *)name ne:(NSString *)value {
return [[[Queries alloc] initWithString:[NSString stringWithFormat:@"(%@ ne '%@')", name, [Utility URLEncode:value]]] autorelease];
}
- (Queries *) and:(Queries *)aQueries {
return [[[Queries alloc] initWithString:[NSString stringWithFormat:@"(%@ and %@)", self.filterString, aQueries.filterString]] autorelease];
}
- (Queries *) or:(Queries *)aQueries {
return [[[Queries alloc] initWithString:[NSString stringWithFormat:@"(%@ or %@)", self.filterString, aQueries.filterString]] autorelease];
}
- (Queries *) not {
return [[[Queries alloc] initWithString:[NSString stringWithFormat:@"(not %@)", self.filterString]] autorelease];
}
- (void) dealloc {
[self.filterString release];
[super dealloc];
}
@end
このクエリビルダを使うと上記のクエリは、
[Queries with:@"PartitionKey" eq:@"あいうえお"].filterString;
と書ける。
0 件のコメント:
コメントを投稿