Skip to content

Commit 689377d

Browse files
author
Alexis Oyama
committed
perf(request): Moving to SQLite
Added LPDatabase for general SQLite access and have LPEventDataManager as DAO. This replaces LPRequestStorage.
1 parent 428fd13 commit 689377d

File tree

10 files changed

+355
-14
lines changed

10 files changed

+355
-14
lines changed

Leanplum-SDK/Classes/Constants.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ OBJC_EXPORT NSString *LEANPLUM_DEFAULTS_SDK_VERSION;
158158
OBJC_EXPORT NSString *LEANPLUM_DEFAULTS_INBOX_KEY;
159159
OBJC_EXPORT NSString *LEANPLUM_DEFAULTS_APP_VERSION_KEY;
160160

161+
OBJC_EXPORT NSString *LEANPLUM_SQLITE_NAME;
162+
161163
OBJC_EXPORT NSString *LP_METHOD_START;
162164
OBJC_EXPORT NSString *LP_METHOD_GET_VARS;
163165
OBJC_EXPORT NSString *LP_METHOD_SET_VARS;

Leanplum-SDK/Classes/Constants.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ - (id)init {
9595
NSString *LEANPLUM_DEFAULTS_INBOX_KEY = @"__leanplum_newsfeed";
9696
NSString *LEANPLUM_DEFAULTS_APP_VERSION_KEY = @"leanplum_savedAppVersionKey";
9797

98+
NSString *LEANPLUM_SQLITE_NAME = @"__leanplum.sqlite";
99+
98100
NSString *LP_METHOD_START = @"start";
99101
NSString *LP_METHOD_GET_VARS = @"getVars";
100102
NSString *LP_METHOD_SET_VARS = @"setVars";

Leanplum-SDK/Classes/LPDatabase.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// LPDatabase.h
3+
// Leanplum
4+
//
5+
// Created by Alexis Oyama on 6/9/17.
6+
// Copyright (c) 2017 Leanplum, Inc. All rights reserved.
7+
//
8+
// Licensed to the Apache Software Foundation (ASF) under one
9+
// or more contributor license agreements. See the NOTICE file
10+
// distributed with this work for additional information
11+
// regarding copyright ownership. The ASF licenses this file
12+
// to you under the Apache License, Version 2.0 (the "License");
13+
// you may not use this file except in compliance with the License.
14+
// You may obtain a copy of the License at
15+
//
16+
// http://www.apache.org/licenses/LICENSE-2.0
17+
//
18+
// Unless required by applicable law or agreed to in writing,
19+
// software distributed under the License is distributed on an
20+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21+
// KIND, either express or implied. See the License for the
22+
// specific language governing permissions and limitations
23+
// under the License.
24+
25+
#import <Foundation/Foundation.h>
26+
27+
@interface LPDatabase : NSObject
28+
{
29+
id sqliteObject;
30+
}
31+
32+
/**
33+
* Returns shared database.
34+
*/
35+
+ (LPDatabase *)database;
36+
37+
/**
38+
* Returns a file path of sqlite from the documents directory.
39+
*/
40+
+ (NSString *)sqliteFilePath;
41+
42+
/**
43+
* Runs a query.
44+
* Use this to create, insert, update, and delete.
45+
*/
46+
- (void)runQuery:(NSString *)query;
47+
48+
/**
49+
* Return rows as array from the query.
50+
* Use this for fetching data.
51+
* Datas are saved as NSDictionary. Key is the column's name.
52+
*/
53+
- (NSArray *)rowsFromQuery:(NSString *)query;
54+
55+
56+
@end

Leanplum-SDK/Classes/LPDatabase.m

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//
2+
// LPDatabase.m
3+
// Leanplum
4+
//
5+
// Created by Alexis Oyama on 6/9/17.
6+
// Copyright (c) 2017 Leanplum, Inc. All rights reserved.
7+
//
8+
// Licensed to the Apache Software Foundation (ASF) under one
9+
// or more contributor license agreements. See the NOTICE file
10+
// distributed with this work for additional information
11+
// regarding copyright ownership. The ASF licenses this file
12+
// to you under the Apache License, Version 2.0 (the "License");
13+
// you may not use this file except in compliance with the License.
14+
// You may obtain a copy of the License at
15+
//
16+
// http://www.apache.org/licenses/LICENSE-2.0
17+
//
18+
// Unless required by applicable law or agreed to in writing,
19+
// software distributed under the License is distributed on an
20+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21+
// KIND, either express or implied. See the License for the
22+
// specific language governing permissions and limitations
23+
// under the License.
24+
25+
#import "LPDatabase.h"
26+
#import "LPFileManager.h"
27+
#import "LeanplumInternal.h"
28+
#import "Constants.h"
29+
#import <sqlite3.h>
30+
31+
@implementation LPDatabase
32+
33+
/**
34+
* Create/Open SQLite database.
35+
*/
36+
- (id)init
37+
{
38+
if (self = [super init]) {
39+
const char *sqliteFilePath = [[LPDatabase sqliteFilePath] UTF8String];
40+
sqlite3 *sqlite;
41+
int result = sqlite3_open(sqliteFilePath, &sqlite);
42+
if (result != SQLITE_OK) {
43+
LPLog(LPError, @"Fail to open SQLite with result of %d", result);
44+
return self;
45+
}
46+
47+
// Create tables.
48+
[self runQuery:@"CREATE TABLE IF NOT EXISTS event ("
49+
"id INTEGER PRIMARY KEY,"
50+
"data TEXT"
51+
");"];
52+
NSLog(@"This is okay?");
53+
}
54+
return self;
55+
}
56+
57+
+ (LPDatabase *)database
58+
{
59+
static id _database = nil;
60+
static dispatch_once_t databaseToken;
61+
dispatch_once(&databaseToken, ^{
62+
_database = [self new];
63+
});
64+
return _database;
65+
}
66+
67+
+ (NSString *)sqliteFilePath
68+
{
69+
return [[LPFileManager documentsDirectory] stringByAppendingPathComponent:LEANPLUM_SQLITE_NAME];
70+
}
71+
72+
/**
73+
* Helper method that returns sqlite statement from query.
74+
* Used by both runQuery: and rowsFromQuery.
75+
*/
76+
- (sqlite3_stmt *)sqliteStatementFromQuery:(NSString *)query
77+
{
78+
const char *sqliteFilePath = [[LPDatabase sqliteFilePath] UTF8String];
79+
sqlite3 *sqlite;
80+
int result = sqlite3_open(sqliteFilePath, &sqlite);
81+
if (result != SQLITE_OK) {
82+
LPLog(LPError, @"Fail to open SQLite with result of %d", result);
83+
return nil;
84+
}
85+
86+
sqlite3_stmt *statement;
87+
result = sqlite3_prepare_v2(sqlite, [query UTF8String], -1, &statement, NULL);
88+
if (result != SQLITE_OK) {
89+
LPLog(LPError, @"Preparing '%@': %s (%d)", query, sqlite3_errmsg(sqlite),
90+
result);
91+
return nil;
92+
}
93+
94+
return statement;
95+
}
96+
97+
- (void)runQuery:(NSString *)query
98+
{
99+
sqlite3_stmt *statement = [self sqliteStatementFromQuery:query];
100+
if (!statement) {
101+
return;
102+
}
103+
104+
int result = sqlite3_step(statement);
105+
if (result != SQLITE_DONE) {
106+
LPLog(LPError, @"Fail to runQuery with result of %d", result);
107+
}
108+
sqlite3_finalize(statement);
109+
}
110+
111+
- (NSArray *)rowsFromQuery:(NSString *)query
112+
{
113+
NSMutableArray *rows = [NSMutableArray new];
114+
sqlite3_stmt *statement = [self sqliteStatementFromQuery:query];
115+
if (!statement) {
116+
return @[];
117+
}
118+
119+
// Iterate through rows.
120+
while (sqlite3_step(statement) == SQLITE_ROW) {
121+
// Get column data as dictionary where column name is the key
122+
// and value will be a string. This is a safe conversion.
123+
// For more details: http://www.sqlite.org/c3ref/column_blob.html
124+
NSMutableDictionary *columnData = [NSMutableDictionary new];
125+
int columnsCount = sqlite3_column_count(statement);
126+
for (int i=0; i<columnsCount; i++){
127+
char *columnKeyUTF8 = (char *)sqlite3_column_name(statement, i);
128+
NSString *columnKey = [NSString stringWithUTF8String:columnKeyUTF8];
129+
130+
char *columnValueUTF8 = (char *)sqlite3_column_text(statement, i);
131+
NSString *columnValue = [NSString stringWithUTF8String:columnValueUTF8];
132+
133+
columnData[columnKey] = columnValue;
134+
}
135+
[rows addObject:columnData];
136+
}
137+
sqlite3_finalize(statement);
138+
139+
return rows;
140+
}
141+
142+
@end
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// LPEventDataManager.h
3+
// Leanplum
4+
//
5+
// Created by Alexis Oyama on 6/9/17.
6+
// Copyright (c) 2017 Leanplum, Inc. All rights reserved.
7+
//
8+
// Licensed to the Apache Software Foundation (ASF) under one
9+
// or more contributor license agreements. See the NOTICE file
10+
// distributed with this work for additional information
11+
// regarding copyright ownership. The ASF licenses this file
12+
// to you under the Apache License, Version 2.0 (the "License");
13+
// you may not use this file except in compliance with the License.
14+
// You may obtain a copy of the License at
15+
//
16+
// http://www.apache.org/licenses/LICENSE-2.0
17+
//
18+
// Unless required by applicable law or agreed to in writing,
19+
// software distributed under the License is distributed on an
20+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21+
// KIND, either express or implied. See the License for the
22+
// specific language governing permissions and limitations
23+
// under the License.
24+
25+
26+
#import <Foundation/Foundation.h>
27+
28+
@interface LPEventDataManager : NSObject
29+
30+
+ (void)addEvent:(NSDictionary *)event;
31+
32+
+ (void)addEvents:(NSArray *)events;
33+
34+
+ (NSArray *)eventsWithLimit:(NSInteger)limit;
35+
36+
+ (void)deleteEventsWithLimit:(NSInteger)limit;
37+
38+
@end
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//
2+
// LPEventDataManager.m
3+
// Leanplum
4+
//
5+
// Created by Alexis Oyama on 6/9/17.
6+
// Copyright (c) 2017 Leanplum, Inc. All rights reserved.
7+
//
8+
// Licensed to the Apache Software Foundation (ASF) under one
9+
// or more contributor license agreements. See the NOTICE file
10+
// distributed with this work for additional information
11+
// regarding copyright ownership. The ASF licenses this file
12+
// to you under the Apache License, Version 2.0 (the "License");
13+
// you may not use this file except in compliance with the License.
14+
// You may obtain a copy of the License at
15+
//
16+
// http://www.apache.org/licenses/LICENSE-2.0
17+
//
18+
// Unless required by applicable law or agreed to in writing,
19+
// software distributed under the License is distributed on an
20+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21+
// KIND, either express or implied. See the License for the
22+
// specific language governing permissions and limitations
23+
// under the License.
24+
25+
#import "LPEventDataManager.h"
26+
#import "LPDatabase.h"
27+
#import "LPJSON.h"
28+
#import "LPRequestStorage.h"
29+
30+
@implementation LPEventDataManager
31+
32+
+ (void)load
33+
{
34+
[LPEventDataManager migrateRequests];
35+
}
36+
37+
+ (void)migrateRequests
38+
{
39+
LPRequestStorage *requestStorage = [LPRequestStorage sharedStorage];
40+
if ([[NSFileManager defaultManager] fileExistsAtPath:requestStorage.documentsFilePath]) {
41+
NSArray *requests = [requestStorage popAllRequests];
42+
[LPEventDataManager addEvents:requests];
43+
}
44+
}
45+
46+
+ (void)addEvent:(NSDictionary *)event
47+
{
48+
NSString *query = [NSString stringWithFormat:@"INSERT INTO event (data) VALUES ('%@')",
49+
[LPJSON stringFromJSON:event]];
50+
[[LPDatabase database] runQuery:query];
51+
}
52+
53+
+ (void)addEvents:(NSArray *)events
54+
{
55+
if (!events.count) {
56+
return;
57+
}
58+
59+
NSMutableString *query = [@"INSERT INTO event (data) VALUES " mutableCopy];
60+
[events enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
61+
NSString *postfix = idx >= events.count-1 ? @";" : @", ";
62+
NSString *valueString = [NSString stringWithFormat:@"(%@)%@",
63+
[LPJSON stringFromJSON:obj], postfix];
64+
[query appendString:valueString];
65+
}];
66+
[[LPDatabase database] runQuery:query];
67+
}
68+
69+
+ (NSArray *)eventsWithLimit:(NSInteger)limit
70+
{
71+
NSString *query = [NSString stringWithFormat:@"SELECT data FROM event ORDER BY id "
72+
"LIMIT %ld", limit];
73+
NSArray *rows = [[LPDatabase database] rowsFromQuery:query];
74+
// Convert row data to event.
75+
NSMutableArray *events = [NSMutableArray new];
76+
for (NSDictionary *row in rows) {
77+
NSDictionary *event = [LPJSON JSONFromString:row[@"data"]];
78+
if (!event || !event.count) {
79+
continue;
80+
}
81+
[events addObject:event];
82+
}
83+
84+
return events;
85+
}
86+
87+
+ (void)deleteEventsWithLimit:(NSInteger)limit
88+
{
89+
NSString *query = [NSString stringWithFormat:@"DELETE FROM event ORDER BY id "
90+
"LIMIT %ld", limit];
91+
[[LPDatabase database] runQuery:query];
92+
}
93+
94+
@end

Leanplum-SDK/Classes/LPRequestStorage.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424

2525
#import <Foundation/Foundation.h>
2626

27+
/**
28+
* Request Storage is deprecated from 2.0.2.
29+
* Use LPEventDataManager instead.
30+
* Do not use this class other than migrating.
31+
*/
2732
@interface LPRequestStorage : NSObject {
2833
@private
2934
NSTimeInterval _lastSentTime;
@@ -48,4 +53,9 @@
4853
*/
4954
- (NSArray *)popAllRequests;
5055

56+
/**
57+
* This file path returns the one in documents directory. Requests should be stored here.
58+
*/
59+
- (NSString *)documentsFilePath;
60+
5161
@end

Leanplum-SDK/Classes/LeanplumRequest.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@
8181
*/
8282
- (void)sendDatasNow:(NSDictionary *)datas;
8383

84-
+ (NSString *)jsonEncodeUnsentRequests:(NSArray *)requestData;
8584
+ (void)pushUnsentRequests:(NSArray *)requestData;
8685

8786
- (void)downloadFile:(NSString *)path;

0 commit comments

Comments
 (0)