- Added new methods that allow a query of a single term over name, address, phone, telegram an website fields

- Linking this result to the code that handles the UI update (working for merchants only)
This commit is contained in:
Nelson R. Perez 2019-01-28 18:34:07 -05:00
parent 07e39e9001
commit aebff15033
8 changed files with 144 additions and 21 deletions

View file

@ -47,6 +47,11 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
// Gradle automatically adds 'android.test.runner' as a dependency.
useLibrary 'android.test.runner'
useLibrary 'android.test.base'
useLibrary 'android.test.mock'
} }
dependencies { dependencies {
@ -100,9 +105,12 @@ dependencies {
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4' debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
// TODO enable and make proper testing // TODO enable and make proper testing
// testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
// Core library
androidTestImplementation 'androidx.test:core:1.1.0'
// testImplementation "androidx.arch.core:core-testing:$lifecycle_version" // testImplementation "androidx.arch.core:core-testing:$lifecycle_version"
// testImplementation "androidx.room:room-testing:$room_version" // testImplementation "androidx.room:room-testing:$room_version"
// androidTestImplementation 'androidx.test:runner:1.1.0' // androidTestImplementation 'androidx.test:runner:1.1.0'
// androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
} }

View file

@ -0,0 +1,65 @@
package cy.agorise.bitsybitshareswallet;
import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.runner.AndroidJUnit4
import cy.agorise.bitsybitshareswallet.database.BitsyDatabase
import cy.agorise.bitsybitshareswallet.database.entities.Merchant
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.io.IOException
@RunWith(AndroidJUnit4::class)
public class MerchantQueryTest {
private lateinit var db: BitsyDatabase
@Before
fun createDb(){
val context = ApplicationProvider.getApplicationContext<Context>()
db = Room.inMemoryDatabaseBuilder(context, BitsyDatabase::class.java).build()
// Creating a few sample merchants
val merchant1 = Merchant("5c23c8c234c83f0013e67786",
"Café del Mar",
"Address1",
17.82834,
-9.38483,
"+1 999.999.9999",
"@user",
"https://100Natural.com")
val merchant2 = Merchant("5c23c91a34c83f0013e67787",
"Condesa Acapulco",
"Address2",
13.82834,
-67.38483,
"+1 999.999.9999",
"@user",
"https://100Natural.com")
db.merchantDao().insert(merchant1)
db.merchantDao().insert(merchant2)
}
@After
@Throws(IOException::class)
fun closeDb(){
db.close()
}
@Test
fun testSimpleQuery(){
val allMerchants = db.merchantDao().getAllSync()
Assert.assertEquals(2, allMerchants.size)
}
@Test
fun testSearchQuery(){
val query = "%con%"
val merchants = db.merchantDao().findMerchantsByWordSync(query)
Assert.assertEquals(1, merchants.size)
Assert.assertEquals(merchants[0].name, "Condesa Acapulco")
}
}

View file

@ -6,6 +6,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
import cy.agorise.bitsybitshareswallet.database.entities.Merchant import cy.agorise.bitsybitshareswallet.database.entities.Merchant
import io.reactivex.Single
@Dao @Dao
interface MerchantDao { interface MerchantDao {
@ -18,6 +19,15 @@ interface MerchantDao {
@Query("SELECT * FROM merchants") @Query("SELECT * FROM merchants")
fun getAll(): LiveData<List<Merchant>> fun getAll(): LiveData<List<Merchant>>
@Query("SELECT * FROM merchants")
fun getAllSync(): List<Merchant>
@Query("SELECT * FROM merchants WHERE (name LIKE :query) OR (address LIKE :query) OR (phone LIKE :query) OR (telegram LIKE :query) OR (website LIKE :query)")
fun findMerchantsByWord(query: String): Single<List<Merchant>>
@Query("SELECT * FROM merchants WHERE (name LIKE :query) OR (address LIKE :query) OR (phone LIKE :query) OR (telegram LIKE :query) OR (website LIKE :query)")
fun findMerchantsByWordSync(query: String): List<Merchant>
@Query("DELETE FROM merchants") @Query("DELETE FROM merchants")
fun deleteAll() fun deleteAll()
} }

View file

@ -6,6 +6,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
import cy.agorise.bitsybitshareswallet.database.entities.Teller import cy.agorise.bitsybitshareswallet.database.entities.Teller
import io.reactivex.Single
@Dao @Dao
interface TellerDao { interface TellerDao {
@ -18,6 +19,9 @@ interface TellerDao {
@Query("SELECT * FROM tellers") @Query("SELECT * FROM tellers")
fun getAll(): LiveData<List<Teller>> fun getAll(): LiveData<List<Teller>>
@Query("SELECT * FROM tellers WHERE (name LIKE :query) OR (address LIKE :query) OR (phone LIKE :query) OR (telegram LIKE :query) OR (website LIKE :query)")
fun findTellersByWord(query: String): Single<List<Teller>>
@Query("DELETE FROM tellers") @Query("DELETE FROM tellers")
fun deleteAll() fun deleteAll()
} }

View file

@ -6,13 +6,8 @@ import android.content.pm.PackageManager
import android.database.Cursor import android.database.Cursor
import android.database.MatrixCursor import android.database.MatrixCursor
import android.os.Bundle import android.os.Bundle
import android.util.Log
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import cy.agorise.bitsybitshareswallet.R
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.util.Log
import android.view.* import android.view.*
import android.widget.PopupWindow import android.widget.PopupWindow
import android.widget.TextView import android.widget.TextView
@ -27,12 +22,18 @@ import androidx.lifecycle.ViewModelProviders
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView import com.afollestad.materialdialogs.customview.customView
import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.model.* import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.maps.model.MapStyleOptions
import com.google.android.gms.maps.model.Marker
import com.google.maps.android.MarkerManager import com.google.maps.android.MarkerManager
import com.google.maps.android.clustering.Cluster import com.google.maps.android.clustering.Cluster
import com.google.maps.android.clustering.ClusterItem import com.google.maps.android.clustering.ClusterItem
import com.google.maps.android.clustering.ClusterManager import com.google.maps.android.clustering.ClusterManager
import com.jakewharton.rxbinding3.appcompat.queryTextChangeEvents import com.jakewharton.rxbinding3.appcompat.queryTextChangeEvents
import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.database.entities.Merchant import cy.agorise.bitsybitshareswallet.database.entities.Merchant
import cy.agorise.bitsybitshareswallet.database.entities.Teller import cy.agorise.bitsybitshareswallet.database.entities.Teller
import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.utils.Constants
@ -42,7 +43,9 @@ import cy.agorise.bitsybitshareswallet.utils.toast
import cy.agorise.bitsybitshareswallet.viewmodels.MerchantViewModel import cy.agorise.bitsybitshareswallet.viewmodels.MerchantViewModel
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import java.lang.Exception import io.reactivex.schedulers.Schedulers
import java.math.BigInteger
import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -173,21 +176,35 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
} }
private fun updateSearchViewSuggestions(query: String) { private fun updateSearchViewSuggestions(query: String) {
// TODO make call to the db to obtain the list of merchants/tellers val merchObs = mMerchantViewModel.queryMerchants(query)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
// Create a cursor out of an Array val tellerObs = mMerchantViewModel.queryTellers(query)
val cursor = MatrixCursor(arrayOf(SUGGEST_COLUMN_ID, SUGGEST_COLUMN_NAME, .subscribeOn(Schedulers.io())
SUGGEST_COLUMN_ADDRESS, SUGGEST_COLUMN_IS_MERCHANT, SUGGEST_COLUMN_IMAGE_RESOURCE)) .observeOn(AndroidSchedulers.mainThread())
for (i in 1..3) { //TODO: Combine the results of both the merchants and teller queries
if (i%2 == 1) // val combined: Observable<List<Any>> = Observable.combineLatest<List<Merchant>, List<Teller>, List<Any>>(merchObs, tellerObs, BiFunction { t1: List<Merchant>, t2:List<Teller> -> Arrays.asList(t1, t2)})
cursor.addRow(arrayOf(i.toString(), "Merchant $i", "Address $i", 1, R.drawable.ic_merchant_pin))
else merchObs.subscribe({list ->
cursor.addRow(arrayOf(i.toString(), "Teller $i", "Address $i", 0, R.drawable.ic_teller_pin)) run {
Log.d(TAG, "list with ${list.size} elements")
val cursor = MatrixCursor(
arrayOf(
SUGGEST_COLUMN_ID, SUGGEST_COLUMN_NAME,
SUGGEST_COLUMN_ADDRESS, SUGGEST_COLUMN_IS_MERCHANT, SUGGEST_COLUMN_IMAGE_RESOURCE
)
)
for (item in list) {
cursor.addRow(arrayOf(BigInteger(item._id, 16).toLong(), item.name, item.address, 1, R.drawable.ic_merchant_pin))
} }
mSearchView?.suggestionsAdapter?.changeCursor(cursor) mSearchView?.suggestionsAdapter?.changeCursor(cursor)
} }
},
{error -> Log.e(TAG, "Error while retrieving autocomplete suggestions. Msg: ${error}")})
}
override fun onSuggestionSelect(position: Int): Boolean { override fun onSuggestionSelect(position: Int): Boolean {
return onSuggestionClick(position) return onSuggestionClick(position)

View file

@ -11,6 +11,7 @@ import cy.agorise.bitsybitshareswallet.database.entities.Merchant
import cy.agorise.bitsybitshareswallet.network.FeathersResponse import cy.agorise.bitsybitshareswallet.network.FeathersResponse
import cy.agorise.bitsybitshareswallet.network.MerchantsWebservice import cy.agorise.bitsybitshareswallet.network.MerchantsWebservice
import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.utils.Constants
import io.reactivex.Single
import retrofit2.Call import retrofit2.Call
import retrofit2.Response import retrofit2.Response
import retrofit2.Retrofit import retrofit2.Retrofit
@ -79,4 +80,8 @@ class MerchantRepository internal constructor(val context: Context) : retrofit2.
return null return null
} }
} }
fun findMerchantsByWord(query: String): Single<List<Merchant>> {
return mMerchantDao.findMerchantsByWord("%$query%")
}
} }

View file

@ -11,6 +11,7 @@ import cy.agorise.bitsybitshareswallet.database.entities.Teller
import cy.agorise.bitsybitshareswallet.network.FeathersResponse import cy.agorise.bitsybitshareswallet.network.FeathersResponse
import cy.agorise.bitsybitshareswallet.network.MerchantsWebservice import cy.agorise.bitsybitshareswallet.network.MerchantsWebservice
import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.utils.Constants
import io.reactivex.Single
import retrofit2.Call import retrofit2.Call
import retrofit2.Response import retrofit2.Response
import retrofit2.Retrofit import retrofit2.Retrofit
@ -79,4 +80,8 @@ class TellerRepository internal constructor(val context: Context) : retrofit2.Ca
return null return null
} }
} }
fun findTellerByWord(word: String): Single<List<Teller>> {
return mTellerDao.findTellersByWord("%$word%")
}
} }

View file

@ -7,6 +7,7 @@ import cy.agorise.bitsybitshareswallet.database.entities.Merchant
import cy.agorise.bitsybitshareswallet.database.entities.Teller import cy.agorise.bitsybitshareswallet.database.entities.Teller
import cy.agorise.bitsybitshareswallet.repositories.MerchantRepository import cy.agorise.bitsybitshareswallet.repositories.MerchantRepository
import cy.agorise.bitsybitshareswallet.repositories.TellerRepository import cy.agorise.bitsybitshareswallet.repositories.TellerRepository
import io.reactivex.Single
class MerchantViewModel(application: Application) : AndroidViewModel(application) { class MerchantViewModel(application: Application) : AndroidViewModel(application) {
private var mMerchantRepository = MerchantRepository(application) private var mMerchantRepository = MerchantRepository(application)
@ -19,4 +20,12 @@ class MerchantViewModel(application: Application) : AndroidViewModel(application
internal fun getAllTellers(): LiveData<List<Teller>> { internal fun getAllTellers(): LiveData<List<Teller>> {
return mTellerRepository.getAll() return mTellerRepository.getAll()
} }
fun queryMerchants(query: String): Single<List<Merchant>> {
return mMerchantRepository.findMerchantsByWord(query)
}
fun queryTellers(query: String): Single<List<Teller>> {
return mTellerRepository.findTellerByWord(query)
}
} }