Implement executeSql command.

Reviewed By: lblasa

Differential Revision: D48310925

fbshipit-source-id: 136b7f09a3a1b886111b6e3cb0e377b73b126e59
This commit is contained in:
Fúlvio Abrahão de Paula
2023-08-14 11:07:07 -07:00
committed by Facebook GitHub Bot
parent 42fb6f09f7
commit 7ba548d6e7
6 changed files with 115 additions and 2 deletions

View File

@@ -6,6 +6,7 @@
*/ */
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include <objc/NSObjCRuntime.h>
@interface DatabaseExecuteSqlResponse : NSObject @interface DatabaseExecuteSqlResponse : NSObject
@@ -15,6 +16,12 @@
@property(nonatomic, strong) NSNumber* insertedId; @property(nonatomic, strong) NSNumber* insertedId;
@property(nonatomic, assign) NSInteger affectedCount; @property(nonatomic, assign) NSInteger affectedCount;
- (instancetype)initWithType:(NSString*)type
columns:(NSArray*)columns
values:(NSArray*)values
insertedId:(NSNumber*)insertedId
affectedCount:(NSInteger)affectedCount;
@end @end
@interface DatabaseExecuteSqlRequest : NSObject @interface DatabaseExecuteSqlRequest : NSObject
@@ -23,5 +30,7 @@
@property(nonatomic, copy, readonly) NSString* value; @property(nonatomic, copy, readonly) NSString* value;
- (instancetype)initWithDatabaseId:(NSInteger)databaseId value:(NSString*)value; - (instancetype)initWithDatabaseId:(NSInteger)databaseId value:(NSString*)value;
+ (DatabaseExecuteSqlRequest*)getExecuteSqlRequestFromDictionary:
(NSDictionary*)dictionary;
@end @end

View File

@@ -6,6 +6,7 @@
*/ */
#include "DatabaseExecuteSql.h" #include "DatabaseExecuteSql.h"
#include <objc/NSObjCRuntime.h>
@implementation DatabaseExecuteSqlResponse @implementation DatabaseExecuteSqlResponse
@@ -39,4 +40,15 @@
return self; return self;
} }
+ (DatabaseExecuteSqlRequest*)getExecuteSqlRequestFromDictionary:
(NSDictionary*)dictionary {
NSInteger databaseId = [dictionary[@"databaseId"] integerValue];
NSString* value = dictionary[@"value"];
if (databaseId <= 0 || value.length == 0) {
return nil;
}
return [[DatabaseExecuteSqlRequest alloc] initWithDatabaseId:databaseId
value:value];
}
@end @end

View File

@@ -11,6 +11,7 @@
@class DatabaseGetTableStructureResponse; @class DatabaseGetTableStructureResponse;
@class DatabaseGetTableInfoResponse; @class DatabaseGetTableInfoResponse;
@class DatabaseGetTableDataResponse; @class DatabaseGetTableDataResponse;
@class DatabaseExecuteSqlResponse;
@protocol DatabaseDriver<NSObject> @protocol DatabaseDriver<NSObject>
- (NSArray<id<DatabaseDescriptor>>*)getDatabases; - (NSArray<id<DatabaseDescriptor>>*)getDatabases;
@@ -32,4 +33,5 @@
reverse:(BOOL)reverse reverse:(BOOL)reverse
start:(NSInteger)start start:(NSInteger)start
count:(NSInteger)count; count:(NSInteger)count;
- (DatabaseExecuteSqlResponse*)executeSQL:(NSString*)sql;
@end @end

View File

@@ -14,6 +14,7 @@
#import "DatabaseDescriptorHolder.h" #import "DatabaseDescriptorHolder.h"
#import "DatabaseDriver.h" #import "DatabaseDriver.h"
#import "DatabaseErrorCodes.h" #import "DatabaseErrorCodes.h"
#import "DatabaseExecuteSql.h"
#import "DatabaseGetTableData.h" #import "DatabaseGetTableData.h"
#import "DatabaseGetTableInfo.h" #import "DatabaseGetTableInfo.h"
#import "DatabaseGetTableStructure.h" #import "DatabaseGetTableStructure.h"
@@ -214,6 +215,37 @@
[self.connection [self.connection
receive:@"execute" receive:@"execute"
withBlock:^(NSDictionary* params, id<FlipperResponder> responder) { withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
DatabaseExecuteSqlRequest* request = [DatabaseExecuteSqlRequest
getExecuteSqlRequestFromDictionary: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 {
DatabaseExecuteSqlResponse* sqlResponse =
[descriptorHolder.databaseDriver executeSQL:request.value];
NSDictionary* response =
[ObjectMapper databaseExecuteSqlResponseToDictionary:sqlResponse];
[responder success:response];
} @catch (NSException* exception) {
NSDictionary* errorResponse = [ObjectMapper
errorWithCode:DatabasesErrorCodesSqlExecutionException
message:[kDatabasesErrorCodesSqlExecutionExceptionMessage
stringByAppendingString:exception.reason]];
[responder error:errorResponse];
}
}]; }];
} }

View File

@@ -6,6 +6,7 @@
*/ */
#import "MockDatabaseDriver.h" #import "MockDatabaseDriver.h"
#import "DatabaseExecuteSql.h"
#import "DatabaseGetTableData.h" #import "DatabaseGetTableData.h"
#import "DatabaseGetTableInfo.h" #import "DatabaseGetTableInfo.h"
#import "DatabaseGetTableStructure.h" #import "DatabaseGetTableStructure.h"
@@ -80,4 +81,39 @@
total:100]; total:100];
} }
- (DatabaseExecuteSqlResponse*)executeSQL:(NSString*)sql {
// Generate a mock response with a random type
NSString* type;
NSArray* columns = @[ @"id", @"name" ];
NSMutableArray* values = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
[values addObject:@[ @(i), [NSString stringWithFormat:@"Name %d", i] ]];
}
// Randomly select a type
NSArray<NSString*>* types = @[ @"SELECT", @"INSERT", @"UPDATE", @"DELETE" ];
int index = arc4random_uniform((u_int32_t)types.count);
type = types[index];
// Set affectedCount and insertedId based on type
NSInteger affectedCount = 0;
NSNumber* insertedId = nil;
if ([type isEqualToString:@"INSERT"]) {
affectedCount = 1;
insertedId = @(15);
} else if (
[type isEqualToString:@"UPDATE"] || [type isEqualToString:@"DELETE"]) {
affectedCount = values.count;
}
DatabaseExecuteSqlResponse* response =
[[DatabaseExecuteSqlResponse alloc] initWithType:type
columns:columns
values:[values copy]
insertedId:insertedId
affectedCount:affectedCount];
return response;
}
@end @end

View File

@@ -83,7 +83,29 @@ static NSString* const UNKNOWN_BLOB_LABEL_FORMAT = @"{%d-byte %@ blob}";
+ (NSDictionary*)databaseExecuteSqlResponseToDictionary: + (NSDictionary*)databaseExecuteSqlResponseToDictionary:
(DatabaseExecuteSqlResponse*)response { (DatabaseExecuteSqlResponse*)response {
return @{}; NSMutableArray* rows = [NSMutableArray array];
if (response.values) {
for (NSArray* row in response.values) {
NSMutableArray* rowValues = [NSMutableArray array];
for (id item in row) {
[rowValues addObject:[self objectAndTypeToFlipperObject:item]];
}
[rows addObject:rowValues];
}
}
NSMutableDictionary* result = [NSMutableDictionary dictionaryWithDictionary:@{
@"type" : response.type,
@"columns" : response.columns,
@"values" : rows,
@"affectedCount" : @(response.affectedCount)
}];
if (response.insertedId) {
result[@"insertedId"] = response.insertedId;
}
return result;
} }
+ (NSDictionary*)objectAndTypeToFlipperObject:(id)object { + (NSDictionary*)objectAndTypeToFlipperObject:(id)object {