Skip to content

Commit eb1f83f

Browse files
Merge pull request #400 from GodotNuts/massive-firestore-refactor
Massive Firestore refactor
2 parents 9f0586e + 19bc818 commit eb1f83f

9 files changed

+527
-405
lines changed

addons/godot-firebase/Utilities.gd

+191
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,189 @@ static func get_json_data(value):
1212
return null
1313

1414

15+
# Pass a dictionary { 'key' : 'value' } to format it in a APIs usable .fields
16+
# Field Path3D using the "dot" (`.`) notation are supported:
17+
# ex. { "PATH.TO.SUBKEY" : "VALUE" } ==> { "PATH" : { "TO" : { "SUBKEY" : "VALUE" } } }
18+
static func dict2fields(dict : Dictionary) -> Dictionary:
19+
var fields = {}
20+
var var_type : String = ""
21+
for field in dict.keys():
22+
var field_value = dict[field]
23+
if field is String and "." in field:
24+
var keys: Array = field.split(".")
25+
field = keys.pop_front()
26+
keys.reverse()
27+
for key in keys:
28+
field_value = { key : field_value }
29+
30+
match typeof(field_value):
31+
TYPE_NIL: var_type = "nullValue"
32+
TYPE_BOOL: var_type = "booleanValue"
33+
TYPE_INT: var_type = "integerValue"
34+
TYPE_FLOAT: var_type = "doubleValue"
35+
TYPE_STRING: var_type = "stringValue"
36+
TYPE_DICTIONARY:
37+
if is_field_timestamp(field_value):
38+
var_type = "timestampValue"
39+
field_value = dict2timestamp(field_value)
40+
else:
41+
var_type = "mapValue"
42+
field_value = dict2fields(field_value)
43+
TYPE_ARRAY:
44+
var_type = "arrayValue"
45+
field_value = {"values": array2fields(field_value)}
46+
47+
if fields.has(field) and fields[field].has("mapValue") and field_value.has("fields"):
48+
for key in field_value["fields"].keys():
49+
fields[field]["mapValue"]["fields"][key] = field_value["fields"][key]
50+
else:
51+
fields[field] = { var_type : field_value }
52+
53+
return {'fields' : fields}
54+
55+
static func from_firebase_type(value : Variant) -> Variant:
56+
if value == null:
57+
return null
58+
59+
if value.has("mapValue"):
60+
value = _from_firebase_type_recursive(value.values()[0].fields)
61+
elif value.has("timestampValue"):
62+
value = Time.get_datetime_dict_from_datetime_string(value.values()[0], false)
63+
else:
64+
value = value.values()[0]
65+
66+
return value
67+
68+
static func _from_firebase_type_recursive(value : Variant) -> Variant:
69+
if value == null:
70+
return null
71+
72+
if value.has("mapValue") or value.has("timestampValue"):
73+
value = _from_firebase_type_recursive(value.value()[0].fields)
74+
else:
75+
value = value.values()[0]
76+
77+
return value
78+
79+
static func to_firebase_type(value : Variant) -> Dictionary:
80+
var var_type : String = ""
81+
82+
match typeof(value):
83+
TYPE_NIL: var_type = "nullValue"
84+
TYPE_BOOL: var_type = "booleanValue"
85+
TYPE_INT: var_type = "integerValue"
86+
TYPE_FLOAT: var_type = "doubleValue"
87+
TYPE_STRING: var_type = "stringValue"
88+
TYPE_DICTIONARY:
89+
if is_field_timestamp(value):
90+
var_type = "timestampValue"
91+
value = dict2timestamp(value)
92+
else:
93+
var_type = "mapValue"
94+
value = dict2fields(value)
95+
TYPE_ARRAY:
96+
var_type = "arrayValue"
97+
value = {"values": array2fields(value)}
98+
99+
return { var_type : value }
100+
101+
# Pass the .fields inside a Firestore Document to print out the Dictionary { 'key' : 'value' }
102+
static func fields2dict(doc) -> Dictionary:
103+
var dict = {}
104+
if doc.has("fields"):
105+
var fields = doc["fields"]
106+
print(fields)
107+
for field in fields.keys():
108+
if fields[field].has("mapValue"):
109+
dict[field] = (fields2dict(fields[field].mapValue))
110+
elif fields[field].has("timestampValue"):
111+
dict[field] = timestamp2dict(fields[field].timestampValue)
112+
elif fields[field].has("arrayValue"):
113+
dict[field] = fields2array(fields[field].arrayValue)
114+
elif fields[field].has("integerValue"):
115+
dict[field] = fields[field].values()[0] as int
116+
elif fields[field].has("doubleValue"):
117+
dict[field] = fields[field].values()[0] as float
118+
elif fields[field].has("booleanValue"):
119+
dict[field] = fields[field].values()[0] as bool
120+
elif fields[field].has("nullValue"):
121+
dict[field] = null
122+
else:
123+
dict[field] = fields[field].values()[0]
124+
return dict
125+
126+
# Pass an Array to parse it to a Firebase arrayValue
127+
static func array2fields(array : Array) -> Array:
128+
var fields : Array = []
129+
var var_type : String = ""
130+
for field in array:
131+
match typeof(field):
132+
TYPE_DICTIONARY:
133+
if is_field_timestamp(field):
134+
var_type = "timestampValue"
135+
field = dict2timestamp(field)
136+
else:
137+
var_type = "mapValue"
138+
field = dict2fields(field)
139+
TYPE_NIL: var_type = "nullValue"
140+
TYPE_BOOL: var_type = "booleanValue"
141+
TYPE_INT: var_type = "integerValue"
142+
TYPE_FLOAT: var_type = "doubleValue"
143+
TYPE_STRING: var_type = "stringValue"
144+
TYPE_ARRAY: var_type = "arrayValue"
145+
_: var_type = "FieldTransform"
146+
fields.append({ var_type : field })
147+
return fields
148+
149+
# Pass a Firebase arrayValue Dictionary to convert it back to an Array
150+
static func fields2array(array : Dictionary) -> Array:
151+
var fields : Array = []
152+
if array.has("values"):
153+
for field in array.values:
154+
var item
155+
match field.keys()[0]:
156+
"mapValue":
157+
item = fields2dict(field.mapValue)
158+
"arrayValue":
159+
item = fields2array(field.arrayValue)
160+
"integerValue":
161+
item = field.values()[0] as int
162+
"doubleValue":
163+
item = field.values()[0] as float
164+
"booleanValue":
165+
item = field.values()[0] as bool
166+
"timestampValue":
167+
item = timestamp2dict(field.timestampValue)
168+
"nullValue":
169+
item = null
170+
_:
171+
item = field.values()[0]
172+
fields.append(item)
173+
return fields
174+
175+
# Converts a gdscript Dictionary (most likely obtained with Time.get_datetime_dict_from_system()) to a Firebase Timestamp
176+
static func dict2timestamp(dict : Dictionary) -> String:
177+
#dict.erase('weekday')
178+
#dict.erase('dst')
179+
#var dict_values : Array = dict.values()
180+
var time = Time.get_datetime_string_from_datetime_dict(dict, false)
181+
return time
182+
#return "%04d-%02d-%02dT%02d:%02d:%02d.00Z" % dict_values
183+
184+
# Converts a Firebase Timestamp back to a gdscript Dictionary
185+
static func timestamp2dict(timestamp : String) -> Dictionary:
186+
return Time.get_datetime_dict_from_datetime_string(timestamp, false)
187+
#var datetime : Dictionary = {year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0}
188+
#var dict : PackedStringArray = timestamp.split("T")[0].split("-")
189+
#dict.append_array(timestamp.split("T")[1].split(":"))
190+
#for value in dict.size():
191+
#datetime[datetime.keys()[value]] = int(dict[value])
192+
#return datetime
193+
194+
static func is_field_timestamp(field : Dictionary) -> bool:
195+
return field.has_all(['year','month','day','hour','minute','second'])
196+
197+
15198
# HTTPRequeust seems to have an issue in Web exports where the body returns empty
16199
# This appears to be caused by the gzip compression being unsupported, so we
17200
# disable it when web export is detected.
@@ -133,3 +316,11 @@ class ObservableDictionary extends RefCounted:
133316
func _set(property: StringName, value: Variant) -> bool:
134317
update(property, value)
135318
return true
319+
320+
class AwaitDetachable extends Node2D:
321+
var awaiter : Signal
322+
323+
func _init(freeable_node, await_signal : Signal) -> void:
324+
awaiter = await_signal
325+
add_child(freeable_node)
326+
awaiter.connect(queue_free)

0 commit comments

Comments
 (0)