티스토리 뷰

안드로이드

[Android] AAC Room @RawQuery: SimpleSQLiteQuery with SELECT projection, WHERE selection

rhyshan

[기존] SQLite문으로 projection 및 selection을 받아 처리


Button btnSelection = findViewById(R.id.button_selection);
btnSelection.setOnClickListener(v -> {
String projection[] = {"ch.title", "title", "ch._id"};
String selection = "WHERE someType IS 1";
Cursor cursor = getApplicationContext().getContentResolver()
.query(uri, projection, selection, null, null);
String cursorToString = DatabaseUtils.dumpCursorToString(cursor);
textView.setText(cursorToString);
});

기존 앱에서 Room으로 DB를 바꾸며, 타 앱에 지원해 오던 ContentProvider를 구현해야 하는데


SQLite문의 projection과 selection으로 처리해오던 query를 받아낼 방법이 없음.





SQL Injection을 막기 위해서인지? Dao의 @Query에 들어가는 변수는 변수로써만 동작.


그러니까 아래 같은 거 안됨.


[X] @Query("SELECT * FROM " + Cheese.TABLE_NAME + " WHERE :selection")
List<Cheese> getItemBySelection(String selection);





[출처 mfamstory] projection - SELECT / selection - WHERE / sortOrder - ORDER BY



또 projection과 selection에서 오는 variation을 처리할 수 있어야 하는데,

parsing 후 필요한 그 모든 메소드를 Dao에 만들어 내려니 노답. 양이 너무 많음.


구글링해도 내게 적용할 방법이 보이질 않아 일단 아래와 같이 처리.





[룸 적용 후] RawQuery 대신 RoomDatabase의 query를 사용


Roomdatabase에 들어있는 이걸 가져다가,


// Below, there are wrapper methods for SupportSQLiteDatabase. This helps us track which
// methods we are using and also helps unit tests to mock this class without mocking
// all SQLite database methods.

/**
* Convenience method to query the database with arguments.
*
* @param query The sql query
* @param args The bind arguments for the placeholders in the query
*
* @return A Cursor obtained by running the given query in the Room database.
*/
public Cursor query(String query, @Nullable Object[] args) {
return mOpenHelper.getWritableDatabase().query(new SimpleSQLiteQuery(query, args));
}

/**
* Wrapper for {@link SupportSQLiteDatabase#query(SupportSQLiteQuery)}.
*
* @param query The Query which includes the SQL and a bind callback for bind arguments.
* @return Result of the query.
*/
public Cursor query(SupportSQLiteQuery query) {
assertNotMainThread();
return mOpenHelper.getWritableDatabase().query(query);
}

android/arch/persistence/room/RoomDatabase.java




외부의 query를 처리할 프로바이더의 query() 부분에 적용.


String columnList = "*";
if (projection != null) {
columnList = projectionToString(projection);
}

if(selection == null) {
selection = "";
}

RoomDatabase mDb = SampleDatabase.getInstance(getContext());
cursor = mDb.query(new SimpleSQLiteQuery("SELECT " + columnList + " FROM " + Cheese.TABLE_NAME + " " + selection));




기존처럼 DB에 RawQuery를 날리기 위해, 하드코딩을 하는 방식.


또, Room으로 DB를 변경하며 테이블 구조와 column명이 바뀌었기에... 들어온 projection, selection 각 String을 마이그레이션하는 작업도 들어가야 한다. 노답(2)



private String projectionToString(String[] projection) {
return String.join(",", new ArrayList<>(Arrays.asList(projection)));
}

-> "ch.title, title, ch._id"





그래서..


연동된 타 앱에 가이드 됐던대로, 기존에 지원하던 대로


CP query()의 projection과 selection을 새로운 RoomDatabase와 함께 사용할 수 있게 되었으나