Implement getTableData command.
Reviewed By: lblasa Differential Revision: D48267029 fbshipit-source-id: a2ee02d3d0c465c83acd99fd7093e0abb5c7c2de
This commit is contained in:
committed by
Facebook GitHub Bot
parent
a0510ad1bf
commit
42fb6f09f7
@@ -39,4 +39,7 @@
|
|||||||
start:(NSInteger)start
|
start:(NSInteger)start
|
||||||
count:(NSInteger)count;
|
count:(NSInteger)count;
|
||||||
|
|
||||||
|
+ (DatabaseGetTableDataRequest*)getTableDataRequestFromDictionary:
|
||||||
|
(NSDictionary*)dictionary;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -47,4 +47,23 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (DatabaseGetTableDataRequest*)getTableDataRequestFromDictionary:
|
||||||
|
(NSDictionary*)dictionary {
|
||||||
|
NSInteger databaseId = [dictionary[@"databaseId"] integerValue];
|
||||||
|
NSString* table = dictionary[@"table"];
|
||||||
|
NSString* order = dictionary[@"order"];
|
||||||
|
BOOL reverse = [dictionary[@"reverse"] boolValue];
|
||||||
|
NSInteger start = [dictionary[@"start"] integerValue];
|
||||||
|
NSInteger count = [dictionary[@"count"] integerValue];
|
||||||
|
if (databaseId <= 0 || table.length == 0) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return [[DatabaseGetTableDataRequest alloc] initWithDatabaseId:databaseId
|
||||||
|
table:table
|
||||||
|
order:order
|
||||||
|
reverse:reverse
|
||||||
|
start:start
|
||||||
|
count:count];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,8 +8,9 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
@protocol DatabaseDescriptor;
|
@protocol DatabaseDescriptor;
|
||||||
@class DatabaseGetTableInfoResponse;
|
|
||||||
@class DatabaseGetTableStructureResponse;
|
@class DatabaseGetTableStructureResponse;
|
||||||
|
@class DatabaseGetTableInfoResponse;
|
||||||
|
@class DatabaseGetTableDataResponse;
|
||||||
|
|
||||||
@protocol DatabaseDriver<NSObject>
|
@protocol DatabaseDriver<NSObject>
|
||||||
- (NSArray<id<DatabaseDescriptor>>*)getDatabases;
|
- (NSArray<id<DatabaseDescriptor>>*)getDatabases;
|
||||||
@@ -22,4 +23,13 @@
|
|||||||
getTableInfoWithDatabaseDescriptor:
|
getTableInfoWithDatabaseDescriptor:
|
||||||
(id<DatabaseDescriptor>)databaseDescriptor
|
(id<DatabaseDescriptor>)databaseDescriptor
|
||||||
forTable:(NSString*)tableName;
|
forTable:(NSString*)tableName;
|
||||||
|
|
||||||
|
- (DatabaseGetTableDataResponse*)
|
||||||
|
getTableDataWithDatabaseDescriptor:
|
||||||
|
(id<DatabaseDescriptor>)databaseDescriptor
|
||||||
|
forTable:(NSString*)tableName
|
||||||
|
order:(NSString*)order
|
||||||
|
reverse:(BOOL)reverse
|
||||||
|
start:(NSInteger)start
|
||||||
|
count:(NSInteger)count;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#import "DatabaseDescriptorHolder.h"
|
#import "DatabaseDescriptorHolder.h"
|
||||||
#import "DatabaseDriver.h"
|
#import "DatabaseDriver.h"
|
||||||
#import "DatabaseErrorCodes.h"
|
#import "DatabaseErrorCodes.h"
|
||||||
|
#import "DatabaseGetTableData.h"
|
||||||
#import "DatabaseGetTableInfo.h"
|
#import "DatabaseGetTableInfo.h"
|
||||||
#import "DatabaseGetTableStructure.h"
|
#import "DatabaseGetTableStructure.h"
|
||||||
#import "ObjectMapper.h"
|
#import "ObjectMapper.h"
|
||||||
@@ -85,8 +86,46 @@
|
|||||||
|
|
||||||
[self.connection
|
[self.connection
|
||||||
receive:@"getTableData"
|
receive:@"getTableData"
|
||||||
withBlock:^(NSDictionary* params, id<FlipperResponder> responder){
|
withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
|
||||||
|
DatabaseGetTableDataRequest* request = [DatabaseGetTableDataRequest
|
||||||
|
getTableDataRequestFromDictionary:params];
|
||||||
|
if (!request) {
|
||||||
|
NSDictionary* errorResponse = [ObjectMapper
|
||||||
|
errorWithCode:DatabasesErrorCodesInvalidRequest
|
||||||
|
message:kDatabasesErrorCodesInvalidRequestMessage];
|
||||||
|
[responder error:errorResponse];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DatabaseDescriptorHolder* descriptorHolder =
|
||||||
|
self.databaseDescriptorHolders[@(request.databaseId)];
|
||||||
|
if (!descriptorHolder) {
|
||||||
|
NSDictionary* errorResponse = [ObjectMapper
|
||||||
|
errorWithCode:DatabasesErrorCodesDatabaseInvalid
|
||||||
|
message:kDatabasesErrorCodesDatabaseInvalidMessage];
|
||||||
|
[responder error:errorResponse];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@try {
|
||||||
|
DatabaseGetTableDataResponse* tableDataResponse =
|
||||||
|
[descriptorHolder.databaseDriver
|
||||||
|
getTableDataWithDatabaseDescriptor:descriptorHolder
|
||||||
|
.databaseDescriptor
|
||||||
|
forTable:request.table
|
||||||
|
order:request.order
|
||||||
|
reverse:request.reverse
|
||||||
|
start:request.start
|
||||||
|
count:request.count];
|
||||||
|
NSDictionary* response = [ObjectMapper
|
||||||
|
databaseGetTableDataResponseToDictionary:tableDataResponse];
|
||||||
|
[responder success:response];
|
||||||
|
} @catch (NSException* exception) {
|
||||||
|
NSDictionary* errorResponse = [ObjectMapper
|
||||||
|
errorWithCode:DatabasesErrorCodesSqlExecutionException
|
||||||
|
message:[kDatabasesErrorCodesSqlExecutionExceptionMessage
|
||||||
|
stringByAppendingString:exception.reason]];
|
||||||
|
[responder error:errorResponse];
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[self.connection
|
[self.connection
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "MockDatabaseDriver.h"
|
#import "MockDatabaseDriver.h"
|
||||||
|
#import "DatabaseGetTableData.h"
|
||||||
#import "DatabaseGetTableInfo.h"
|
#import "DatabaseGetTableInfo.h"
|
||||||
#import "DatabaseGetTableStructure.h"
|
#import "DatabaseGetTableStructure.h"
|
||||||
#import "MockDatabaseDescriptor.h"
|
#import "MockDatabaseDescriptor.h"
|
||||||
@@ -55,4 +56,28 @@
|
|||||||
initWithDefinition:@"This is mocked table definition"];
|
initWithDefinition:@"This is mocked table definition"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (DatabaseGetTableDataResponse*)
|
||||||
|
getTableDataWithDatabaseDescriptor:
|
||||||
|
(id<DatabaseDescriptor>)databaseDescriptor
|
||||||
|
forTable:(NSString*)tableName
|
||||||
|
order:(NSString*)order
|
||||||
|
reverse:(BOOL)reverse
|
||||||
|
start:(NSInteger)start
|
||||||
|
count:(NSInteger)count {
|
||||||
|
NSMutableArray* columns = [NSMutableArray array];
|
||||||
|
NSMutableArray* values = [NSMutableArray array];
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
NSString* columnName = [NSString stringWithFormat:@"column%d", i + 1];
|
||||||
|
[columns addObject:columnName];
|
||||||
|
NSArray* valueRow = @[ @"value1", @"value2", @"value3" ];
|
||||||
|
[values addObject:valueRow];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [[DatabaseGetTableDataResponse alloc] initWithColumns:[columns copy]
|
||||||
|
values:[values copy]
|
||||||
|
start:0
|
||||||
|
count:100
|
||||||
|
total:100];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
|
|
||||||
@implementation ObjectMapper
|
@implementation ObjectMapper
|
||||||
|
|
||||||
|
static const int MAX_BLOB_LENGTH = 100 * 1024;
|
||||||
|
static NSString* const UNKNOWN_BLOB_LABEL_FORMAT = @"{%d-byte %@ blob}";
|
||||||
|
|
||||||
+ (NSMutableArray*)databaseListToFlipperArray:
|
+ (NSMutableArray*)databaseListToFlipperArray:
|
||||||
(NSMutableSet<DatabaseDescriptorHolder*>*)databaseDescriptorHolderSet {
|
(NSMutableSet<DatabaseDescriptorHolder*>*)databaseDescriptorHolderSet {
|
||||||
NSMutableArray* result = [NSMutableArray new];
|
NSMutableArray* result = [NSMutableArray new];
|
||||||
@@ -39,7 +42,22 @@
|
|||||||
|
|
||||||
+ (NSDictionary*)databaseGetTableDataResponseToDictionary:
|
+ (NSDictionary*)databaseGetTableDataResponseToDictionary:
|
||||||
(DatabaseGetTableDataResponse*)response {
|
(DatabaseGetTableDataResponse*)response {
|
||||||
return @{};
|
NSMutableArray* rows = [NSMutableArray array];
|
||||||
|
for (NSArray* row in response.values) {
|
||||||
|
NSMutableArray* rowValues = [NSMutableArray array];
|
||||||
|
for (id item in row) {
|
||||||
|
[rowValues addObject:[self objectAndTypeToFlipperObject:item]];
|
||||||
|
}
|
||||||
|
[rows addObject:rowValues];
|
||||||
|
}
|
||||||
|
|
||||||
|
return @{
|
||||||
|
@"columns" : response.columns,
|
||||||
|
@"values" : rows,
|
||||||
|
@"start" : @(response.start),
|
||||||
|
@"count" : @(response.count),
|
||||||
|
@"total" : @(response.total)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSDictionary*)errorWithCode:(NSInteger)code message:(NSString*)message {
|
+ (NSDictionary*)errorWithCode:(NSInteger)code message:(NSString*)message {
|
||||||
@@ -68,4 +86,72 @@
|
|||||||
return @{};
|
return @{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary*)objectAndTypeToFlipperObject:(id)object {
|
||||||
|
if (!object) {
|
||||||
|
return @{@"type" : @"null"};
|
||||||
|
} else if ([object isKindOfClass:[NSNumber class]]) {
|
||||||
|
NSNumber* number = (NSNumber*)object;
|
||||||
|
NSString* type = [NSString stringWithCString:[number objCType]];
|
||||||
|
|
||||||
|
if ([type isEqualToString:@"i"]) {
|
||||||
|
return @{@"type" : @"integer", @"value" : number};
|
||||||
|
} else if ([type isEqualToString:@"f"] || [type isEqualToString:@"d"]) {
|
||||||
|
return @{@"type" : @"float", @"value" : number};
|
||||||
|
} else if ([type isEqualToString:@"B"]) {
|
||||||
|
return @{@"type" : @"boolean", @"value" : number};
|
||||||
|
} else {
|
||||||
|
return @{@"type" : @"integer", @"value" : @([number integerValue])};
|
||||||
|
}
|
||||||
|
|
||||||
|
return @{@"type" : @"integer", @"value" : object};
|
||||||
|
} else if ([object isKindOfClass:[NSDecimalNumber class]]) {
|
||||||
|
return @{@"type" : @"float", @"value" : object};
|
||||||
|
} else if ([object isKindOfClass:[NSString class]]) {
|
||||||
|
return @{@"type" : @"string", @"value" : object};
|
||||||
|
} else if ([object isKindOfClass:[NSData class]]) {
|
||||||
|
NSString* blobString = [self blobToString:(NSData*)object];
|
||||||
|
return @{@"type" : @"blob", @"value" : blobString};
|
||||||
|
} else if ([object isKindOfClass:[NSValue class]]) {
|
||||||
|
return @{@"type" : @"boolean", @"value" : object};
|
||||||
|
} else {
|
||||||
|
@throw [NSException exceptionWithName:@"InvalidArgumentException"
|
||||||
|
reason:@"type of Object is invalid"
|
||||||
|
userInfo:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString*)blobToString:(NSData*)data {
|
||||||
|
const uint8_t* bytes = data.bytes;
|
||||||
|
uint length = data.length;
|
||||||
|
|
||||||
|
if (length <= MAX_BLOB_LENGTH) {
|
||||||
|
if ([self fastIsAscii:bytes length:length]) {
|
||||||
|
NSStringEncoding encoding = NSASCIIStringEncoding;
|
||||||
|
return [[NSString alloc] initWithBytesNoCopy:(void*)bytes
|
||||||
|
length:length
|
||||||
|
encoding:encoding
|
||||||
|
freeWhenDone:NO];
|
||||||
|
} else {
|
||||||
|
// try UTF-8
|
||||||
|
NSStringEncoding encoding = NSUTF8StringEncoding;
|
||||||
|
return [[NSString alloc] initWithBytesNoCopy:(void*)bytes
|
||||||
|
length:length
|
||||||
|
encoding:encoding
|
||||||
|
freeWhenDone:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
[NSString stringWithFormat:UNKNOWN_BLOB_LABEL_FORMAT, length, @"binary"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)fastIsAscii:(const uint8_t*)bytes length:(NSUInteger)length {
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
uint8_t b = bytes[i];
|
||||||
|
if ((b & ~0x7f) != 0) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Reference in New Issue
Block a user