<commit_before>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

MODEL({
  name: 'GMailRestDAO',
  extendsModel: 'RestDAO',

  properties: [
    {
      name: 'url',
      defaultValue: 'https://www.googleapis.com/gmail/v1/users'
    },
    {
      name: 'xhr',
      factory: function() { return this.X.XHR.create({ responseType: 'json' }); }
    }
  ],

  methods: {
    buildURL: function() {
      return this.url + '/me/' + this.model.plural;
    },
    buildSelectParams: function(sink, query) {
      var params = [];
      if ( CountExpr.isInstance(sink) ) params.push('maxResults=1');
      if ( GMailHistory.isSubModel(this.model) &&
           GtExpr.isInstance(query) &&
           query.arg1 === GMailHistory.ID ) {
        params.push('startHistoryId=' + query.arg2.f());
      }
      // TODO: Split MQLable queries apart from non MQLable queries.
      // if ( query ) params.push('q=' + encodeURIComponent(query.toMQL()));
      return params;
    },
    select: function(sink, options) {
      sink = sink || [];

      if ( options && ! CountExpr.isInstance(sink) ) sink = this.decorateSink_(sink, options);

      options = options || {};
      var urlParams = options.urlParams || [];
      options.limit && urlParams.push('maxResults=' + options.limit);
      var params = this.buildSelectParams(sink, options.query);
      var url = this.buildURL();

      var fc = this.createFlowControl_();
      var self = this;
      var future = afuture();
      var pageToken;

      awhile(
        function() { return ! fc.stopped && ! fc.errorEvt; },
        aseq(
          function(ret) {
            var p = pageToken ? params.concat('pageToken=' + pageToken) : params;
            self.xhr.asend(ret, url + "?" + p.join('&'));
          },
          function(ret, data) {
            if ( ! data || ! data[self.model.plural] ) {
              fc.error("No data");
              ret();
              return;
            }

            if ( CountExpr.isInstance(sink) ) {
              sink.count = data.resultSizeEstimate;
              fc.stop();
            }

            var items = data[self.model.plural];
            var i = 0;

            pageToken = data.nextPageToken;

            awhile(function() { return i < items.length; },
                   function(ret) {
                     if ( fc.stopped ) {
                       i = items.length;
                       ret();
                       return;
                     }
                     if ( fc.errorEvt ) {
                       sink.error && sink.error(fc.errorEvt);
                       i = items.length;
                       ret();
                       return;
                     }
                     self.onSelectData(ret, items[i++], sink, fc);
                   })(ret);
          },
          function(ret) {
            if (!pageToken) {
              fc.stop();
            }
            ret();
          }))(function() {
            sink.eof && sink.eof();
            future.set(sink);
          });

      return future.get;
    },
    onSelectData: function(ret, data, sink, fc) {
      sink.put && sink.put(this.jsonToObj(data), null, fc);
      ret();
    },
    find: function(key, sink, options) {
      options = options || {};
      var self = this;
      var obj;
      aseq(
        function(ret) {
          self.xhr.asend(
            ret,
            self.buildFindURL(key) +
              "?" + self.buildFindParams(options.urlParams).join('&'));
        },
        function(ret, response, xhr) {
          if ( ! response ) {
            sink && sink.error & sink.error(['Failed to find message.', xhr.status]);
            return;
          }
          obj = self.jsonToObj(response);
          sink && sink.put && sink.put(obj);
          ret();
        })(function(){});
    },
    buildFindURL: function(key) {
      return this.url + '/me/' + this.model.plural + '/' + key;
    },
    buildFindParams: function(urlParams) {
      var params = urlParams || [];
      return params;
    },
  }
});

MODEL({
  name: 'FOAMGMailMessage',
  extendsModel: 'GMailMessage',
  plural: 'messages',

  properties: [
    { model_: 'StringProperty', name: 'messageId' },
    { model_: 'BooleanProperty', name: 'isDraft', defaultValue: false },
    { model_: 'BooleanProperty', name: 'isSent', defaultValue: false }
  ],

  methods: {
    toRaw: function() {
      var buffer = "";

      function doPart(p) {
        for ( var i = 0, header; header = p.headers[i]; i++ ) {
          buffer += header.name + ": " + header.value + "\r\n";
          if ( header.name === "Content-Type" && header.value.startsWith("multipart") )
            var boundary = header.value.match(/boundary=([\S]+)/)[1];
        }
        buffer += "\r\n";

        if ( p.body && p.body.size > 0 ) {
          var decoder = Base64Decoder.create(IncrementalUtf8.create(), p.body.size);
          decoder.put(p.body.data);
          decoder.eof();

          buffer += decoder.sink.string;
        }<commit_msg>Remove unused isDraft property from FOAMGMailMessage<commit_after>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

MODEL({
  name: 'GMailRestDAO',
  extendsModel: 'RestDAO',

  properties: [
    {
      name: 'url',
      defaultValue: 'https://www.googleapis.com/gmail/v1/users'
    },
    {
      name: 'xhr',
      factory: function() { return this.X.XHR.create({ responseType: 'json' }); }
    }
  ],

  methods: {
    buildURL: function() {
      return this.url + '/me/' + this.model.plural;
    },
    buildSelectParams: function(sink, query) {
      var params = [];
      if ( CountExpr.isInstance(sink) ) params.push('maxResults=1');
      if ( GMailHistory.isSubModel(this.model) &&
           GtExpr.isInstance(query) &&
           query.arg1 === GMailHistory.ID ) {
        params.push('startHistoryId=' + query.arg2.f());
      }
      // TODO: Split MQLable queries apart from non MQLable queries.
      // if ( query ) params.push('q=' + encodeURIComponent(query.toMQL()));
      return params;
    },
    select: function(sink, options) {
      sink = sink || [];

      if ( options && ! CountExpr.isInstance(sink) ) sink = this.decorateSink_(sink, options);

      options = options || {};
      var urlParams = options.urlParams || [];
      options.limit && urlParams.push('maxResults=' + options.limit);
      var params = this.buildSelectParams(sink, options.query);
      var url = this.buildURL();

      var fc = this.createFlowControl_();
      var self = this;
      var future = afuture();
      var pageToken;

      awhile(
        function() { return ! fc.stopped && ! fc.errorEvt; },
        aseq(
          function(ret) {
            var p = pageToken ? params.concat('pageToken=' + pageToken) : params;
            self.xhr.asend(ret, url + "?" + p.join('&'));
          },
          function(ret, data) {
            if ( ! data || ! data[self.model.plural] ) {
              fc.error("No data");
              ret();
              return;
            }

            if ( CountExpr.isInstance(sink) ) {
              sink.count = data.resultSizeEstimate;
              fc.stop();
            }

            var items = data[self.model.plural];
            var i = 0;

            pageToken = data.nextPageToken;

            awhile(function() { return i < items.length; },
                   function(ret) {
                     if ( fc.stopped ) {
                       i = items.length;
                       ret();
                       return;
                     }
                     if ( fc.errorEvt ) {
                       sink.error && sink.error(fc.errorEvt);
                       i = items.length;
                       ret();
                       return;
                     }
                     self.onSelectData(ret, items[i++], sink, fc);
                   })(ret);
          },
          function(ret) {
            if (!pageToken) {
              fc.stop();
            }
            ret();
          }))(function() {
            sink.eof && sink.eof();
            future.set(sink);
          });

      return future.get;
    },
    onSelectData: function(ret, data, sink, fc) {
      sink.put && sink.put(this.jsonToObj(data), null, fc);
      ret();
    },
    find: function(key, sink, options) {
      options = options || {};
      var self = this;
      var obj;
      aseq(
        function(ret) {
          self.xhr.asend(
            ret,
            self.buildFindURL(key) +
              "?" + self.buildFindParams(options.urlParams).join('&'));
        },
        function(ret, response, xhr) {
          if ( ! response ) {
            sink && sink.error & sink.error(['Failed to find message.', xhr.status]);
            return;
          }
          obj = self.jsonToObj(response);
          sink && sink.put && sink.put(obj);
          ret();
        })(function(){});
    },
    buildFindURL: function(key) {
      return this.url + '/me/' + this.model.plural + '/' + key;
    },
    buildFindParams: function(urlParams) {
      var params = urlParams || [];
      return params;
    },
  }
});

MODEL({
  name: 'FOAMGMailMessage',
  extendsModel: 'GMailMessage',
  plural: 'messages',

  properties: [
    { model_: 'StringProperty', name: 'messageId' },
    { model_: 'BooleanProperty', name: 'isSent', defaultValue: false }
  ],

  methods: {
    toRaw: function() {
      var buffer = "";

      function doPart(p) {
        for ( var i = 0, header; header = p.headers[i]; i++ ) {
          buffer += header.name + ": " + header.value + "\r\n";
          if ( header.name === "Content-Type" && header.value.startsWith("multipart") )
            var boundary = header.value.match(/boundary=([\S]+)/)[1];
        }
        buffer += "\r\n";

        if ( p.body && p.body.size > 0 ) {
          var decoder = Base64Decoder.create(IncrementalUtf8.create(), p.body.size);
          decoder.put(p.body.data);
          decoder.eof();

          buffer += decoder.sink.string;
        }
{'fraction_non_alphanumeric': 0.14321608040201006, 'fraction_numerical': 0.0034099066762383347, 'mean_word_length': 1.7477810650887573, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3168839', 'n_tokens_mistral': 3314, 'n_tokens_neox': 3229, 'n_words': 753}