110 lines
3.3 KiB
GDScript
110 lines
3.3 KiB
GDScript
## @meta-authors TODO
|
|
## @meta-version 2.2
|
|
## Data structure that holds the currently-known data at a given path (a.k.a. reference) in a Firebase Realtime Database.
|
|
## Can process both puts and patches into the data based checked realtime events received from the service.
|
|
@tool
|
|
class_name FirebaseDatabaseStore
|
|
extends Node
|
|
|
|
const _DELIMITER : String = "/"
|
|
const _ROOT : String = "_root"
|
|
|
|
## @default false
|
|
## Whether the store is in debug mode.
|
|
var debug : bool = false
|
|
var _data : Dictionary = { }
|
|
|
|
|
|
## @args path, payload
|
|
## Puts a new payload into this data store at the given path. Any existing values in this data store
|
|
## at the specified path will be completely erased.
|
|
func put(path : String, payload) -> void:
|
|
_update_data(path, payload, false)
|
|
|
|
## @args path, payload
|
|
## Patches an update payload into this data store at the specified path.
|
|
## NOTE: When patching in updates to arrays, payload should contain the entire new array! Updating single elements/indexes of an array is not supported. Sometimes when manually mutating array data directly from the Firebase Realtime Database console, single-element patches will be sent out which can cause issues here.
|
|
func patch(path : String, payload) -> void:
|
|
_update_data(path, payload, true)
|
|
|
|
## @args path, payload
|
|
## Deletes data at the reference point provided
|
|
## NOTE: This will delete without warning, so make sure the reference is pointed to the level you want and not the root or you will lose everything
|
|
func delete(path : String, payload) -> void:
|
|
_update_data(path, payload, true)
|
|
|
|
## Returns a deep copy of this data store's payload.
|
|
func get_data() -> Dictionary:
|
|
return _data[_ROOT].duplicate(true)
|
|
|
|
#
|
|
# Updates this data store by either putting or patching the provided payload into it at the given
|
|
# path. The provided payload can technically be any value.
|
|
#
|
|
func _update_data(path: String, payload, patch: bool) -> void:
|
|
if debug:
|
|
print("Updating data store (patch = %s) (%s = %s)..." % [patch, path, payload])
|
|
|
|
#
|
|
# Remove any leading separators.
|
|
#
|
|
path = path.lstrip(_DELIMITER)
|
|
|
|
#
|
|
# Traverse the path.
|
|
#
|
|
var dict = _data
|
|
var keys = PackedStringArray([_ROOT])
|
|
|
|
keys.append_array(path.split(_DELIMITER, false))
|
|
|
|
var final_key_idx = (keys.size() - 1)
|
|
var final_key = (keys[final_key_idx])
|
|
|
|
keys.remove_at(final_key_idx)
|
|
|
|
for key in keys:
|
|
if !dict.has(key):
|
|
dict[key] = { }
|
|
|
|
dict = dict[key]
|
|
|
|
#
|
|
# Handle non-patch (a.k.a. put) mode and then update the destination value.
|
|
#
|
|
var new_type = typeof(payload)
|
|
|
|
if !patch:
|
|
dict.erase(final_key)
|
|
|
|
if new_type == TYPE_NIL:
|
|
dict.erase(final_key)
|
|
elif new_type == TYPE_DICTIONARY:
|
|
if !dict.has(final_key):
|
|
dict[final_key] = { }
|
|
|
|
_update_dictionary(dict[final_key], payload)
|
|
else:
|
|
dict[final_key] = payload
|
|
|
|
if debug:
|
|
print("...Data store updated (%s)." % _data)
|
|
|
|
#
|
|
# Helper method to "blit" changes in an update dictionary payload onto an original dictionary.
|
|
# Parameters are directly changed via reference.
|
|
#
|
|
func _update_dictionary(original_dict: Dictionary, update_payload: Dictionary) -> void:
|
|
for key in update_payload.keys():
|
|
var val_type = typeof(update_payload[key])
|
|
|
|
if val_type == TYPE_NIL:
|
|
original_dict.erase(key)
|
|
elif val_type == TYPE_DICTIONARY:
|
|
if !original_dict.has(key):
|
|
original_dict[key] = { }
|
|
|
|
_update_dictionary(original_dict[key], update_payload[key])
|
|
else:
|
|
original_dict[key] = update_payload[key]
|