Котлин и военнослужащих облачные функции Update() метод


Я использую Kotlin для генерации кода Javascript для функции Firebase cloud.

Я хотел бы вызвать методupdate , передавая некоторые значения в качестве аргументов. В Kotlin я должен передать карту в качестве аргумента update ():

val map = mutableMapOf<String,Int>() //also tried with a Hashmap: same result

//generate some values
for(i in 0 until 3){ 
    map.put("key$i", i)
}
console.log(map.keys.toList().toString()) //log map keys
console.log(map.values.toList().toString()) //log map values

ref.child("values").update(map)

Kotlin генерирует этот код javascript:

var LinkedHashMap_init = Kotlin.kotlin.collections.LinkedHashMap_init_q3lmfv$;
function main$lambda(event){
    var map = LinkedHashMap_init();
    for (var i = 0; i < 3; i++) {
      map.put_xwzc9p$('key' + i, i);
    }
    console.log(toList(map.keys).toString());
    console.log(toList(map.values).toString());
    ref.child('values').update(map);
}

В моей консоли Firebase, вот результат 2 журналов. Это, по-видимому, указывает на то, что карта верна:

[key0, key1, key2]
[0, 1, 2]

Но update() не работает: журналы функций показывают, что сообщение:

Error: Reference.update failed: First argument  contains an invalid key (this$AbstractMutableMap) in property 'games.test.values._keys_qe2m0n$_0'.  Keys must be non-empty strings and can't contain ".", "#", "$", "/", "[", or "]"
    at /user_code/node_modules/firebase-admin/node_modules/@firebase/database/dist/cjs/src/core/util/validation.js:139:27
    at Object.exports.forEach (/user_code/node_modules/firebase-admin/node_modules/@firebase/util/dist/cjs/src/obj.js:37:13)
    at Object.exports.validateFirebaseData (/user_code/node_modules/firebase-admin/node_modules/@firebase/database/dist/cjs/src/core/util/validation.js:132:16)
    at /user_code/node_modules/firebase-admin/node_modules/@firebase/database/dist/cjs/src/core/util/validation.js:223:17
    at Object.exports.forEach (/user_code/node_modules/firebase-admin/node_modules/@firebase/util/dist/cjs/src/obj.js:37:13)
    at Object.exports.validateFirebaseMergeDataArg (/user_code/node_modules/firebase-admin/node_modules/@firebase/database/dist/cjs/src/core/util/validation.js:221:12)
    at Reference.update (/user_code/node_modules/firebase-admin/node_modules/@firebase/database/dist/cjs/src/api/Reference.js:140:22)
    at main$lambda (/user_code/index.js:87:25)
    at Object.<anonymous> (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:59:27)
    at next (native)

Но, наконец, если я вручную пишу код js в функцию, она работает:

var map = {}
for (var i = 0; i < 3; i++) {
    map["key"+i] = i
}
ref.child("values").update(map)

С уважением.

2 2

2 ответа:

Котлин, по-видимому, делаетLinkedHashMap из вашего вызова mutableMapOf.

update() принимает объект JavaScript, обычные, простые свойства которого должны использоваться для обновления документа.

Я совершенно уверен, что реализация LinkedHashMap в JavaScript имеет много свойств объекта, которые будут нарушать указанное ограничение, как вы можете видеть из сообщения об ошибке. Вы не можете просто передать любой объект, который вы хотите update(). Вам нужно сдать объект, содержащий только ключи и значения, которые вы хотите update(). Метод просто не ожидает чего-то сложного, как LinkedHashMap. Вместо этого вам нужно будет написать что-то, что компилируется до простого объекта JavaScript.

Может быть, это было бы полезно прочитать.

Благодаря ответу Дуга, я написал этот маленький фрагмент, чтобы обернуть простой объект javascript key/value в типизированный объект Kotlin:

class JsWrapperMap<K, V> {
    private val map: dynamic = js("({})")

    operator fun get(key: K): V = map[key]
    operator fun set(key: K, value: V) {
        map[key] = value
    }

    fun toJs(): dynamic = map
}

/**
 * Returns an empty new [JsWrapperMap]
 */
fun <K, V> jsMapOf(): JsWrapperMap<K, V> = JsWrapperMap()

/**
 * Returns an empty new [JsWrapperMap] of type <Any, Any>
 */
fun jsMapOfAny(): JsWrapperMap<Any, Any> = JsWrapperMap()

Его можно использовать следующим образом:

val map = jsMapOf<String, Int>()
map["key_0"] = 12
map["key_1"] = 36
ref.child("values").update(map.toJs()) 

Я открыт для любых предложений по этому коду:)