Add getTableInfo API to process incoming TableInfo queries

Summary: Getting the "definition" of the database was originally on the GetTableStructure endpoint. This diff moves it to a new GetTableInfo endpoint

Reviewed By: jknoxville

Differential Revision: D15902619

fbshipit-source-id: ac136d24ee577711366636801b5d74d83fbc523f
This commit is contained in:
Arnaud Frugier
2019-06-20 08:25:11 -07:00
committed by Facebook Github Bot
parent a2663ea970
commit f40ac0617c
5 changed files with 142 additions and 27 deletions

View File

@@ -45,6 +45,9 @@ public abstract class DatabaseDriver<DESCRIPTOR extends DatabaseDescriptor> {
public abstract DatabaseGetTableStructureResponse getTableStructure(
DESCRIPTOR databaseDescriptor, String table);
public abstract DatabaseGetTableInfoResponse getTableInfo(
DESCRIPTOR databaseDescriptor, String table);
public abstract DatabaseExecuteSqlResponse executeSQL(
DESCRIPTOR databaseDescriptor, String query);
@@ -76,18 +79,24 @@ public abstract class DatabaseDriver<DESCRIPTOR extends DatabaseDescriptor> {
public final List<List<Object>> structureValues;
public final List<String> indexesColumns;
public final List<List<Object>> indexesValues;
public final String definition;
public DatabaseGetTableStructureResponse(
final List<String> structureColumns,
final List<List<Object>> structureValues,
final List<String> indexesColumns,
final List<List<Object>> indexesValues,
String definition) {
final List<List<Object>> indexesValues) {
this.structureColumns = structureColumns;
this.structureValues = structureValues;
this.indexesColumns = indexesColumns;
this.indexesValues = indexesValues;
}
}
public static class DatabaseGetTableInfoResponse {
public final String definition;
public DatabaseGetTableInfoResponse(String definition) {
this.definition = definition;
}
}

View File

@@ -14,6 +14,7 @@ import com.facebook.flipper.core.FlipperReceiver;
import com.facebook.flipper.core.FlipperResponder;
import com.facebook.flipper.plugins.databases.DatabaseDriver.DatabaseExecuteSqlResponse;
import com.facebook.flipper.plugins.databases.DatabaseDriver.DatabaseGetTableDataResponse;
import com.facebook.flipper.plugins.databases.DatabaseDriver.DatabaseGetTableInfoResponse;
import com.facebook.flipper.plugins.databases.DatabaseDriver.DatabaseGetTableStructureResponse;
import java.util.Comparator;
import java.util.List;
@@ -26,6 +27,7 @@ public class DatabasesManager {
private static final String DATABASE_LIST_COMMAND = "databaseList";
private static final String GET_TABLE_DATA_COMMAND = "getTableData";
private static final String GET_TABLE_STRUCTURE_COMMAND = "getTableStructure";
private static final String GET_TABLE_INFO_COMMAND = "getTableInfo";
private static final String EXECUTE_COMMAND = "execute";
private final List<DatabaseDriver> mDatabaseDriverList;
@@ -152,7 +154,7 @@ public class DatabasesManager {
databaseDescriptorHolder.databaseDescriptor,
getTableStructureRequest.table);
responder.success(
ObjectMapper.databaseGetTableStructureReponseToFlipperObject(
ObjectMapper.databaseGetTableStructureResponseToFlipperObject(
databaseGetTableStructureResponse));
} catch (Exception e) {
responder.error(
@@ -163,6 +165,43 @@ public class DatabasesManager {
}
}
});
connection.receive(
GET_TABLE_INFO_COMMAND,
new FlipperReceiver() {
@Override
public void onReceive(FlipperObject params, FlipperResponder responder) {
GetTableInfoRequest getTableInfoRequest =
ObjectMapper.flipperObjectToGetTableInfoRequest(params);
if (getTableInfoRequest == null) {
responder.error(
ObjectMapper.toErrorFlipperObject(
DatabasesErrorCodes.ERROR_INVALID_REQUEST,
DatabasesErrorCodes.ERROR_INVALID_REQUEST_MESSAGE));
} else {
DatabaseDescriptorHolder databaseDescriptorHolder =
mDatabaseDescriptorHolderSparseArray.get(getTableInfoRequest.databaseId);
if (databaseDescriptorHolder == null) {
responder.error(
ObjectMapper.toErrorFlipperObject(
DatabasesErrorCodes.ERROR_DATABASE_INVALID,
DatabasesErrorCodes.ERROR_DATABASE_INVALID_MESSAGE));
} else {
try {
DatabaseGetTableInfoResponse databaseGetTableInfoResponse =
databaseDescriptorHolder.databaseDriver.getTableInfo(
databaseDescriptorHolder.databaseDescriptor, getTableInfoRequest.table);
responder.success(
ObjectMapper.databaseGetTableInfoResponseToFlipperObject(
databaseGetTableInfoResponse));
} catch (Exception e) {
responder.error(
ObjectMapper.toErrorFlipperObject(
DatabasesErrorCodes.ERROR_SQL_EXECUTION_EXCEPTION, e.getMessage()));
}
}
}
}
});
connection.receive(
EXECUTE_COMMAND,
new FlipperReceiver() {
@@ -257,4 +296,15 @@ public class DatabasesManager {
this.table = table;
}
}
static class GetTableInfoRequest {
public final int databaseId;
public final String table;
GetTableInfoRequest(int databaseId, String table) {
this.databaseId = databaseId;
this.table = table;
}
}
}

View File

@@ -12,10 +12,12 @@ import com.facebook.flipper.core.FlipperArray.Builder;
import com.facebook.flipper.core.FlipperObject;
import com.facebook.flipper.plugins.databases.DatabaseDriver.DatabaseExecuteSqlResponse;
import com.facebook.flipper.plugins.databases.DatabaseDriver.DatabaseGetTableDataResponse;
import com.facebook.flipper.plugins.databases.DatabaseDriver.DatabaseGetTableInfoResponse;
import com.facebook.flipper.plugins.databases.DatabaseDriver.DatabaseGetTableStructureResponse;
import com.facebook.flipper.plugins.databases.DatabasesManager.DatabaseDescriptorHolder;
import com.facebook.flipper.plugins.databases.DatabasesManager.ExecuteSqlRequest;
import com.facebook.flipper.plugins.databases.DatabasesManager.GetTableDataRequest;
import com.facebook.flipper.plugins.databases.DatabasesManager.GetTableInfoRequest;
import com.facebook.flipper.plugins.databases.DatabasesManager.GetTableStructureRequest;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
@@ -76,6 +78,15 @@ public class ObjectMapper {
return new GetTableStructureRequest(databaseId, table);
}
public static GetTableInfoRequest flipperObjectToGetTableInfoRequest(FlipperObject params) {
int databaseId = params.getInt("databaseId");
String table = params.getString("table");
if (databaseId <= 0 || TextUtils.isEmpty(table)) {
return null;
}
return new GetTableInfoRequest(databaseId, table);
}
public static ExecuteSqlRequest flipperObjectToExecuteSqlRequest(FlipperObject params) {
int databaseId = params.getInt("databaseId");
String value = params.getString("value");
@@ -111,7 +122,7 @@ public class ObjectMapper {
.build();
}
public static FlipperObject databaseGetTableStructureReponseToFlipperObject(
public static FlipperObject databaseGetTableStructureResponseToFlipperObject(
DatabaseGetTableStructureResponse databaseGetTableStructureResponse) {
FlipperArray.Builder structureColumnBuilder = new FlipperArray.Builder();
@@ -147,7 +158,14 @@ public class ObjectMapper {
.put("structureValues", structureValuesBuilder.build())
.put("indexesColumns", indexesColumnBuilder.build())
.put("indexesValues", indexesValuesBuilder.build())
.put("definition", databaseGetTableStructureResponse.definition)
.build();
}
public static FlipperObject databaseGetTableInfoResponseToFlipperObject(
DatabaseGetTableInfoResponse databaseGetTableInfoResponse) {
return new FlipperObject.Builder()
.put("definition", databaseGetTableInfoResponse.definition)
.build();
}

View File

@@ -171,9 +171,7 @@ public class SqliteDatabaseDriver extends DatabaseDriver<SqliteDatabaseDescripto
Cursor structureCursor = database.rawQuery("PRAGMA table_info(" + table + ")", null);
Cursor foreignKeysCursor = database.rawQuery("PRAGMA foreign_key_list(" + table + ")", null);
Cursor indexesCursor = database.rawQuery("PRAGMA index_list(" + table + ")", null);
Cursor definitionCursor =
database.rawQuery(
"SELECT sql FROM " + SCHEMA_TABLE + " WHERE name=?", new String[] {table});
try {
// Structure & foreign keys
@@ -234,13 +232,9 @@ public class SqliteDatabaseDriver extends DatabaseDriver<SqliteDatabaseDescripto
}
}
// Definition
definitionCursor.moveToFirst();
String definition = definitionCursor.getString(definitionCursor.getColumnIndex("sql"));
return new DatabaseGetTableStructureResponse(
structureColumns, structureValues, indexesColumns, indexesValues, definition);
structureColumns, structureValues, indexesColumns, indexesValues);
} finally {
structureCursor.close();
foreignKeysCursor.close();
@@ -251,6 +245,31 @@ public class SqliteDatabaseDriver extends DatabaseDriver<SqliteDatabaseDescripto
}
}
@Override
public DatabaseGetTableInfoResponse getTableInfo(
SqliteDatabaseDescriptor databaseDescriptor, String table) {
SQLiteDatabase database =
sqliteDatabaseConnectionProvider.openDatabase(databaseDescriptor.file);
try {
Cursor definitionCursor =
database.rawQuery(
"SELECT sql FROM " + SCHEMA_TABLE + " WHERE name=?", new String[] {table});
try {
// Definition
definitionCursor.moveToFirst();
String definition = definitionCursor.getString(definitionCursor.getColumnIndex("sql"));
return new DatabaseGetTableInfoResponse(definition);
} finally {
definitionCursor.close();
}
} finally {
database.close();
}
}
private static List<File> tidyDatabaseList(List<File> databaseFiles) {
Set<File> originalAsSet = new HashSet<>(databaseFiles);
List<File> tidiedList = new ArrayList<>();

View File

@@ -12,7 +12,6 @@ import static org.junit.Assert.assertThat;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.test.core.app.ApplicationProvider;
import com.facebook.flipper.core.FlipperArray;
import com.facebook.flipper.core.FlipperObject;
import com.facebook.flipper.plugins.databases.DatabaseDriver.DatabaseExecuteSqlResponse;
@@ -29,6 +28,7 @@ import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
@Ignore
@@ -45,28 +45,26 @@ public class DatabasesFlipperPluginTest {
connectionMock = new FlipperConnectionMock();
responderMock = new FlipperResponderMock();
databaseHelper1 =
new DatabaseHelper(ApplicationProvider.getApplicationContext(), "database1.db");
databaseHelper1 = new DatabaseHelper(RuntimeEnvironment.application, "database1.db");
databaseHelper1
.getWritableDatabase()
.execSQL("INSERT INTO first_table (column1, column2) VALUES('a','b')");
databaseHelper2 =
new DatabaseHelper(ApplicationProvider.getApplicationContext(), "database2.db");
databaseHelper2 = new DatabaseHelper(RuntimeEnvironment.application, "database2.db");
databaseHelper2
.getWritableDatabase()
.execSQL("INSERT INTO first_table (column1, column2) VALUES('a','b')");
plugin =
new DatabasesFlipperPlugin(
new SqliteDatabaseDriver(
ApplicationProvider.getApplicationContext(),
RuntimeEnvironment.application,
new SqliteDatabaseProvider() {
@Override
public List<File> getDatabaseFiles() {
return Arrays.asList(
ApplicationProvider.getApplicationContext()
.getDatabasePath(databaseHelper1.getDatabaseName()),
ApplicationProvider.getApplicationContext()
.getDatabasePath(databaseHelper2.getDatabaseName()));
RuntimeEnvironment.application.getDatabasePath(
databaseHelper1.getDatabaseName()),
RuntimeEnvironment.application.getDatabasePath(
databaseHelper2.getDatabaseName()));
}
}));
@@ -76,8 +74,8 @@ public class DatabasesFlipperPluginTest {
@After
public void tearDown() {
databaseHelper1.close();
ApplicationProvider.getApplicationContext().deleteDatabase(databaseHelper1.getDatabaseName());
ApplicationProvider.getApplicationContext().deleteDatabase(databaseHelper2.getDatabaseName());
RuntimeEnvironment.application.deleteDatabase(databaseHelper1.getDatabaseName());
RuntimeEnvironment.application.deleteDatabase(databaseHelper2.getDatabaseName());
}
@Test
@@ -361,6 +359,27 @@ public class DatabasesFlipperPluginTest {
.put("value", "column1,column2"))
.build())
.build())
.build()));
}
@Test
public void testCommandGetTableInfo() throws Exception {
// Arrange
connectionMock.receivers.get("databaseList").onReceive(null, responderMock); // Load data
// Act
connectionMock
.receivers
.get("getTableInfo")
.onReceive(
new FlipperObject.Builder().put("databaseId", 1).put("table", "first_table").build(),
responderMock);
// Assert
assertThat(
responderMock.successes,
hasItem(
new FlipperObject.Builder()
.put(
"definition",
"CREATE TABLE first_table (_id INTEGER PRIMARY KEY AUTOINCREMENT,column1 TEXT,column2 TEXT)")