Files
fps_project_1/addons/godot-firebase/firestore/firestore_collection.gd

179 lines
5.8 KiB
GDScript

## @meta-authors TODO
## @meta-authors TODO
## @meta-version 2.3
## A reference to a Firestore Collection.
## Documentation TODO.
@tool
class_name FirestoreCollection
extends Node
signal error(error_result)
const _AUTHORIZATION_HEADER : String = "Authorization: Bearer "
const _separator : String = "/"
const _query_tag : String = "?"
const _documentId_tag : String = "documentId="
var auth : Dictionary
var collection_name : String
var _base_url : String
var _extended_url : String
var _config : Dictionary
var _documents := {}
# ----------------------- Requests
## @args document_id
## @return FirestoreTask
## used to GET a document from the collection, specify @document_id
func get_doc(document_id : String, from_cache : bool = false, is_listener : bool = false) -> FirestoreDocument:
if from_cache:
# for now, just return the child directly; in the future, make it smarter so there's a default, if long, polling time for this
for child in get_children():
if child.doc_name == document_id:
return child
var task : FirestoreTask = FirestoreTask.new()
task.action = FirestoreTask.Task.TASK_GET
task.data = collection_name + "/" + document_id
var url = _get_request_url() + _separator + document_id.replace(" ", "%20")
_process_request(task, document_id, url)
var result = await Firebase.Firestore._handle_task_finished(task)
if result != null:
for child in get_children():
if child.doc_name == document_id:
child.replace(result, true)
result = child
break
else:
print("get_document returned null for %s %s" % [collection_name, document_id])
return result
## @args document_id, fields
## @arg-defaults , {}
## @return FirestoreDocument
## used to ADD a new document to the collection, specify @documentID and @data
func add(document_id : String, data : Dictionary = {}) -> FirestoreDocument:
var task : FirestoreTask = FirestoreTask.new()
task.action = FirestoreTask.Task.TASK_POST
task.data = collection_name + "/" + document_id
var url = _get_request_url() + _query_tag + _documentId_tag + document_id
_process_request(task, document_id, url, JSON.stringify(Utilities.dict2fields(data)))
var result = await Firebase.Firestore._handle_task_finished(task)
if result != null:
for child in get_children():
if child.doc_name == document_id:
child.free() # Consider throwing an error for this since it shouldn't already exist
break
result.collection_name = collection_name
add_child(result, true)
return result
## @args document
## @return FirestoreDocument
# used to UPDATE a document, specify the document
func update(document : FirestoreDocument) -> FirestoreDocument:
var task : FirestoreTask = FirestoreTask.new()
task.action = FirestoreTask.Task.TASK_PATCH
task.data = collection_name + "/" + document.doc_name
var url = _get_request_url() + _separator + document.doc_name.replace(" ", "%20") + "?"
for key in document.keys():
url+="updateMask.fieldPaths={key}&".format({key = key})
url = url.rstrip("&")
for key in document.keys():
if document.get_value(key) == null:
document._erase(key)
var temp_transforms
if document._transforms != null:
temp_transforms = document._transforms
document._transforms = null
var body = JSON.stringify({"fields": document.document})
_process_request(task, document.doc_name, url, body)
var result = await Firebase.Firestore._handle_task_finished(task)
if result != null:
for child in get_children():
if child.doc_name == result.doc_name:
child.replace(result, true)
break
if temp_transforms != null:
result._transforms = temp_transforms
return result
## @args document
## @return Dictionary
# Used to commit changes from transforms, specify the document with the transforms
func commit(document : FirestoreDocument) -> Dictionary:
var task : FirestoreTask = FirestoreTask.new()
task.action = FirestoreTask.Task.TASK_COMMIT
var url = get_database_url("commit")
document._transforms.set_config(
{
"extended_url": _extended_url,
"collection_name": collection_name
}
) # Only place we can set this is here, oofness
var body = document._transforms.serialize()
document.clear_field_transforms()
_process_request(task, document.doc_name, url, JSON.stringify(body))
return await Firebase.Firestore._handle_task_finished(task) # Not implementing the follow-up get here as user may have a listener that's already listening for changes, but user should call get if they don't
## @args document_id
## @return FirestoreTask
# used to DELETE a document, specify the document
func delete(document : FirestoreDocument) -> bool:
var doc_name = document.doc_name
var task : FirestoreTask = FirestoreTask.new()
task.action = FirestoreTask.Task.TASK_DELETE
task.data = document.collection_name + "/" + doc_name
var url = _get_request_url() + _separator + doc_name.replace(" ", "%20")
_process_request(task, doc_name, url)
var result = await Firebase.Firestore._handle_task_finished(task)
# Clean up the cache
if result:
for node in get_children():
if node.doc_name == doc_name:
node.free() # Should be only one
break
return result
func _get_request_url() -> String:
return _base_url + _extended_url + collection_name
func _process_request(task : FirestoreTask, document_id : String, url : String, fields := "") -> void:
if auth == null or auth.is_empty():
Firebase._print("Unauthenticated request issued...")
Firebase.Auth.login_anonymous()
var result : Array = await Firebase.Auth.auth_request
if result[0] != 1:
Firebase.Firestore._check_auth_error(result[0], result[1])
return
Firebase._print("Client authenticated as Anonymous User.")
task._url = url
task._fields = fields
task._headers = PackedStringArray([_AUTHORIZATION_HEADER + auth.idtoken])
Firebase.Firestore._pooled_request(task)
func get_database_url(append) -> String:
return _base_url + _extended_url.rstrip("/") + ":" + append