88
99require "elastic_graph/graphql/decoded_cursor"
1010require "elastic_graph/support/memoizable_data"
11+ require "elastic_graph/support/hash_util"
1112require "forwardable"
1213
1314module ElasticGraph
1415 class GraphQL
1516 module DatastoreResponse
17+ DOCUMENT_MISSING_VALUE = ::Object . new . freeze
18+
1619 # Represents a document fetched from the datastore. Exposes both the raw metadata
1720 # provided by the datastore and the doc payload itself. In addition, you can treat
1821 # it just like a document hash using `#[]` or `#fetch`.
1922 Document = Support ::MemoizableData . define ( :raw_data , :payload , :decoded_cursor_factory ) do
2023 # @implements Document
2124 extend Forwardable
2225
23- def_delegators :payload , :[] , :fetch
24-
2526 def self . build ( raw_data , decoded_cursor_factory : DecodedCursor ::Factory ::Null )
2627 source = raw_data . fetch ( "_source" ) do
2728 { } # : ::Hash[::String, untyped]
@@ -51,6 +52,33 @@ def id
5152 raw_data [ "_id" ]
5253 end
5354
55+ def []( key )
56+ fetch ( key ) { nil }
57+ end
58+
59+ def fetch ( key , default_value = DOCUMENT_MISSING_VALUE )
60+ value = lookup_value_at ( [ key ] , list : false , missing_value : DOCUMENT_MISSING_VALUE )
61+ return value unless value . equal? ( DOCUMENT_MISSING_VALUE )
62+ return yield ( key ) if block_given?
63+ return default_value unless default_value . equal? ( DOCUMENT_MISSING_VALUE )
64+
65+ raise KeyError , "key not found: #{ key } "
66+ end
67+
68+ def fetch_value_at ( path , list :, default_value : DOCUMENT_MISSING_VALUE )
69+ value = lookup_value_at ( path , list : list , missing_value : DOCUMENT_MISSING_VALUE )
70+ return value unless value . equal? ( DOCUMENT_MISSING_VALUE )
71+ return yield ( path ) if block_given?
72+ return default_value unless default_value . equal? ( DOCUMENT_MISSING_VALUE )
73+
74+ raise KeyError , "path not found: #{ path . join ( "." ) } "
75+ end
76+
77+ def value_at ( path , list :)
78+ value = lookup_value_at ( path , list : list , missing_value : DOCUMENT_MISSING_VALUE )
79+ value . equal? ( DOCUMENT_MISSING_VALUE ) ? nil : value
80+ end
81+
5482 def sort
5583 raw_data [ "sort" ]
5684 end
@@ -77,6 +105,18 @@ def to_s
77105 "#<#{ self . class . name } #{ datastore_path } >"
78106 end
79107 alias_method :inspect , :to_s
108+
109+ private
110+
111+ def lookup_value_at ( path , list :, missing_value :)
112+ value = Support ::HashUtil . fetch_value_at_path ( payload , path ) { missing_value }
113+ return value unless value . equal? ( missing_value )
114+
115+ field_values = raw_data . fetch ( "fields" , { } ) . fetch ( path . join ( "." ) , missing_value )
116+ return missing_value if field_values . equal? ( missing_value )
117+
118+ list ? field_values : field_values . first
119+ end
80120 end
81121 end
82122 end
0 commit comments