| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta http-equiv="content-type" content="text/html;charset=utf-8"> |
| <title>matching_queries_to_indexes</title> |
| <link rel="stylesheet" href="/css/pycco.css"> |
| </head> |
| <body> |
| <div id="background"></div> |
| <div id='container'> |
| <div class='section'> |
| <div class='docs'><h1>matching_queries_to_indexes</h1></div> |
| </div> |
| <div class='clearall'> |
| <div class='section' id='section-0'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-0'>#</a> |
| </div> |
| <p>If you have not yet seen the source in <a href="/examples/basic_with_auth.html">basic_with_auth</a> and |
| <a href="/examples/paging.html">paging</a>, please take a look.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-1'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-1'>#</a> |
| </div> |
| <p>In this sample we use a custom <code>Enum</code> for the <code>order</code> property in queries |
| to strictly control the indexes used and make sure we have corresponding |
| indexes created in <code>index.yaml</code>.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-2'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-2'>#</a> |
| </div> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre><span class="kn">import</span> <span class="n">endpoints</span> |
| <span class="kn">from</span> <span class="nn">google.appengine.ext</span> <span class="kn">import</span> <span class="n">ndb</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-3'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-3'>#</a> |
| </div> |
| <p>This import allows us to define our own <code>Enum</code> using the ProtoRPC messages |
| library. This is not usually needed, since <code>EndpointsModel</code> handles message |
| definition, but in this case it is.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre><span class="kn">from</span> <span class="nn">protorpc</span> <span class="kn">import</span> <span class="n">messages</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-4'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-4'>#</a> |
| </div> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> |
| <span class="kn">from</span> <span class="nn">protorpc</span> <span class="kn">import</span> <span class="n">remote</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-5'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-5'>#</a> |
| </div> |
| <p>We import <code>EndpointsAliasProperty</code> so that we can define our own helper property |
| similar to the properties <code>id</code>, <code>entityKey</code>, <code>limit</code>, <code>order</code> and <code>pageToken</code> |
| provided by <code>EndpointsModel</code>.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre><span class="kn">from</span> <span class="nn">endpoints_proto_datastore.ndb</span> <span class="kn">import</span> <span class="n">EndpointsAliasProperty</span> |
| </pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-6'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-6'>#</a> |
| </div> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> |
| <span class="kn">from</span> <span class="nn">endpoints_proto_datastore.ndb</span> <span class="kn">import</span> <span class="n">EndpointsModel</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-7'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-7'>#</a> |
| </div> |
| <p>This is an <code>Enum</code> used to strictly define which order values are allowed. |
| In this case, we are only allowing two query orders and have an enum value |
| corresponding to each.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre><span class="k">class</span> <span class="nc">Order</span><span class="p">(</span><span class="n">messages</span><span class="o">.</span><span class="n">Enum</span><span class="p">):</span> |
| <span class="n">MYFIRST</span> <span class="o">=</span> <span class="mi">1</span> |
| <span class="n">MYSECOND</span> <span class="o">=</span> <span class="mi">2</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-8'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-8'>#</a> |
| </div> |
| |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre><span class="k">class</span> <span class="nc">MyModel</span><span class="p">(</span><span class="n">EndpointsModel</span><span class="p">):</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-9'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-9'>#</a> |
| </div> |
| <p>As in <a href="/examples/simple_get.html">simple_get</a>, by setting <code>_message_fields_schema</code>, we can set a |
| custom ProtoRPC message schema. We set the schema to the four properties |
| corresponding to the NDB properties and exclude the fifth property, which is |
| the alias property <code>order</code>. Though the helper property <code>order</code> from |
| <code>EndpointsModel</code> is not included in the message schema, since we define our |
| own <code>order</code>, this would be included if we did not define our own schema.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="n">_message_fields_schema</span> <span class="o">=</span> <span class="p">(</span><span class="s">'attr1'</span><span class="p">,</span> <span class="s">'attr2'</span><span class="p">,</span> <span class="s">'owner'</span><span class="p">,</span> <span class="s">'created'</span><span class="p">)</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-10'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-10'>#</a> |
| </div> |
| <p>The properties <code>attr1</code> and <code>attr2</code> are required here so that all entities will |
| have values for performing queries.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="n">attr1</span> <span class="o">=</span> <span class="n">ndb</span><span class="o">.</span><span class="n">StringProperty</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> |
| <span class="n">attr2</span> <span class="o">=</span> <span class="n">ndb</span><span class="o">.</span><span class="n">StringProperty</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> |
| <span class="n">created</span> <span class="o">=</span> <span class="n">ndb</span><span class="o">.</span><span class="n">DateTimeProperty</span><span class="p">(</span><span class="n">auto_now_add</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-11'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-11'>#</a> |
| </div> |
| <p>As in <a href="/examples/basic_with_auth.html">basic_with_auth</a>, an <code>owner</code> property is used and each entity |
| created will have the current user saved as the <code>owner</code>. As with <code>attr1</code> and |
| <code>attr2</code> above, we are also requiring the <code>owner</code> field so we can use it for |
| queries too.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="n">owner</span> <span class="o">=</span> <span class="n">ndb</span><span class="o">.</span><span class="n">UserProperty</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-12'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-12'>#</a> |
| </div> |
| <p>This is a setter which will be used by the helper property <code>order</code>, which we |
| are overriding here. The setter used for that helper property is also named |
| <code>OrderSet</code>. This method will be called when <code>order</code> is set from a ProtoRPC |
| query request.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="k">def</span> <span class="nf">OrderSet</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-13'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-13'>#</a> |
| </div> |
| <p>Since we wish to control which queries are made, we only accept values |
| from our custom <code>Enum</code> type <code>Order</code>.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">Order</span><span class="p">):</span> |
| <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s">'Expected an enum, received: </span><span class="si">%s</span><span class="s">.'</span> <span class="o">%</span> <span class="p">(</span><span class="n">value</span><span class="p">,))</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-14'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-14'>#</a> |
| </div> |
| <p>For <code>MYFIRST</code>, we order by <code>attr1</code>.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="n">Order</span><span class="o">.</span><span class="n">MYFIRST</span><span class="p">:</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-15'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-15'>#</a> |
| </div> |
| <p>Use the method <code>OrderSet</code> from the parent class to set the string value |
| based on the enum.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="nb">super</span><span class="p">(</span><span class="n">MyModel</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">OrderSet</span><span class="p">(</span><span class="s">'attr1'</span><span class="p">)</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-16'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-16'>#</a> |
| </div> |
| <p>For <code>MYSECOND</code>, we order by <code>attr2</code>, but in descending order.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="k">elif</span> <span class="n">value</span> <span class="o">==</span> <span class="n">Order</span><span class="o">.</span><span class="n">MYSECOND</span><span class="p">:</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-17'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-17'>#</a> |
| </div> |
| <p>Use the method <code>OrderSet</code> from the parent class to set the string value |
| based on the enum.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="nb">super</span><span class="p">(</span><span class="n">MyModel</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">OrderSet</span><span class="p">(</span><span class="s">'-attr2'</span><span class="p">)</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-18'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-18'>#</a> |
| </div> |
| <p>For either case, the order used here will be combined with an equality |
| filter based on the current user, and we have the corresponding indexes specified in |
| <code>index.yaml</code> so no index errors are experienced by our users.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-19'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-19'>#</a> |
| </div> |
| <p>If the value is not a valid <code>Enum</code> value, raise a <code>TypeError</code>. This should |
| never occur since <code>value</code> is known to be an instance of <code>Order</code>.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="k">else</span><span class="p">:</span> |
| <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s">'Unexpected value of Order: </span><span class="si">%s</span><span class="s">.'</span> <span class="o">%</span> <span class="p">(</span><span class="n">value</span><span class="p">,))</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-20'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-20'>#</a> |
| </div> |
| <p>This <code>EndpointsAliasProperty</code> is our own helper property and overrides the |
| original <code>order</code>. We specify the <code>setter</code> as the function <code>OrderSet</code> which we |
| just defined. The <code>property_type</code> is the class <code>Order</code> and the default value of |
| the alias property is <code>MYFIRST</code>.</p> |
| |
| <p>Endpoints alias properties must have a corresponding property type, which |
| can be either a ProtoRPC field or a ProtoRPC message class or enum class. |
| Here, by providing a property type of <code>Order</code>, we aid in the creation of a |
| field corresponding to this property in a ProtoRPC message schema.</p> |
| |
| <p>The <code>EndpointsAliasProperty</code> can be used as a decorator as is done here, or |
| can be used in the same way NDB properties are, e.g. |
| <br> <code>attr1 = ndb.StringProperty()</code><br> |
| and the similar |
| <br> <code>order = EndpointsAliasProperty(OrderGet, setter=OrderSet, ...)</code><br> |
| where <code>OrderGet</code> would be the function defined here.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="nd">@EndpointsAliasProperty</span><span class="p">(</span><span class="n">setter</span><span class="o">=</span><span class="n">OrderSet</span><span class="p">,</span> <span class="n">property_type</span><span class="o">=</span><span class="n">Order</span><span class="p">,</span> |
| <span class="n">default</span><span class="o">=</span><span class="n">Order</span><span class="o">.</span><span class="n">MYFIRST</span><span class="p">)</span> |
| <span class="k">def</span> <span class="nf">order</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-21'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-21'>#</a> |
| </div> |
| <p>We only need to limit the values to <code>Order</code> enums, so we can use the getter |
| from the helper property with no changes.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">MyModel</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">order</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-22'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-22'>#</a> |
| </div> |
| <p>Since we are using auth, we want to test with the |
| <a href="https://developers.google.com/apis-explorer/">Google APIs Explorer</a>. |
| By default, if <code>allowed_client_ids</code> is not specified, this is |
| enabled by default. If you specify <code>allowed_client_ids</code>, you'll |
| need to include <code>endpoints.API_EXPLORER_CLIENT_ID</code> in this list. |
| This is necessary for auth tokens obtained by the API Explorer (on behalf of |
| users) to be considered valid by our API.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre><span class="nd">@endpoints.api</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">'myapi'</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s">'v1'</span><span class="p">,</span> <span class="n">description</span><span class="o">=</span><span class="s">'My Little API'</span><span class="p">,</span> |
| <span class="n">audiences</span><span class="o">=</span><span class="p">[</span><span class="n">endpoints</span><span class="o">.</span><span class="n">API_EXPLORER_CLIENT_ID</span><span class="p">])</span> |
| <span class="k">class</span> <span class="nc">MyApi</span><span class="p">(</span><span class="n">remote</span><span class="o">.</span><span class="n">Service</span><span class="p">):</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-23'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-23'>#</a> |
| </div> |
| <p>We specify that <code>request_fields</code> is <code>('attr1', 'attr2')</code> because the <code>created</code> value is set |
| when the entity is put to the datastore and the <code>owner</code> is set from the |
| current user. As in <a href="/examples/basic_with_auth.html">basic_with_auth</a>, since <code>user_required</code> is set to <code>True</code>, the |
| current user will always be valid.</p> |
| |
| <p>Since no <code>response_fields</code> are set, the four fields from |
| <code>_message_fields_schema</code> will be sent in the response.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="nd">@MyModel.method</span><span class="p">(</span><span class="n">request_fields</span><span class="o">=</span><span class="p">(</span><span class="s">'attr1'</span><span class="p">,</span> <span class="s">'attr2'</span><span class="p">),</span> |
| <span class="n">user_required</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> |
| <span class="n">path</span><span class="o">=</span><span class="s">'mymodel'</span><span class="p">,</span> <span class="n">http_method</span><span class="o">=</span><span class="s">'POST'</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">'mymodel.insert'</span><span class="p">)</span> |
| <span class="k">def</span> <span class="nf">MyModelInsert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">my_model</span><span class="p">):</span> |
| <span class="n">my_model</span><span class="o">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">endpoints</span><span class="o">.</span><span class="n">get_current_user</span><span class="p">()</span> |
| <span class="n">my_model</span><span class="o">.</span><span class="n">put</span><span class="p">()</span> |
| <span class="k">return</span> <span class="n">my_model</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-24'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-24'>#</a> |
| </div> |
| <p>As in <a href="/examples/paging.html">paging</a>, we use the fields <code>limit</code>, <code>order</code> and <code>pageToken</code> for |
| paging, but here <code>order</code> is the <code>Enum</code>-based property we defined above. As |
| mentioned in the definition of <code>OrderSet</code>, these <code>order</code> values are coupled with |
| the filter for current user.</p> |
| |
| <p>Since no <code>collection_fields</code> are set, each value in <code>items</code> in the response |
| will use the four fields from <code>_message_fields_schema</code>.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="nd">@MyModel.query_method</span><span class="p">(</span><span class="n">query_fields</span><span class="o">=</span><span class="p">(</span><span class="s">'limit'</span><span class="p">,</span> <span class="s">'order'</span><span class="p">,</span> <span class="s">'pageToken'</span><span class="p">),</span> |
| <span class="n">user_required</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> |
| <span class="n">path</span><span class="o">=</span><span class="s">'mymodels'</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">'mymodel.list'</span><span class="p">)</span> |
| <span class="k">def</span> <span class="nf">MyModelList</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">query</span><span class="p">):</span></pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-25'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-25'>#</a> |
| </div> |
| <p>Current user is valid since <code>user_required</code> is set to <code>True</code>.</p> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> <span class="k">return</span> <span class="n">query</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">MyModel</span><span class="o">.</span><span class="n">owner</span> <span class="o">==</span> <span class="n">endpoints</span><span class="o">.</span><span class="n">get_current_user</span><span class="p">())</span> |
| |
| </pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-26'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-26'>#</a> |
| </div> |
| </div> |
| <div class='code'> |
| <div class="highlight"><pre> |
| <span class="n">application</span> <span class="o">=</span> <span class="n">endpoints</span><span class="o">.</span><span class="n">api_server</span><span class="p">([</span><span class="n">MyApi</span><span class="p">],</span> <span class="n">restricted</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> |
| </pre></div> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| <div class='section' id='section-27'> |
| <div class='docs'> |
| <div class='octowrap'> |
| <a class='octothorpe' href='#section-27'>#</a> |
| </div> |
| <p>Head on to the next sample <a href="/examples/custom_alias_properties.html">custom_alias_properties<a> |
| or head back to the <a href="/">main page</a>.</p> |
| </div> |
| </div> |
| <div class='clearall'></div> |
| </div> |
| </body> |