<commit_before>// @
// Copyright (c) 2017 Google Inc. All rights reserved.
// This code may only be used under the BSD style license found at
// http://polymer.github.io/LICENSE.txt
// Code distributed by Google as part of this project is also
// subject to an additional IP rights grant found at
// http://polymer.github.io/PATENTS.txt

import {StorageProviderBase} from './storage-provider-base.js';
import {firebase} from '../../platform/firebase-web.js';
import {assert} from '../../platform/assert-web.js';
import {KeyBase} from './key-base.js';
import {atob} from '../../platform/atob-web.js';
import {btoa} from '../../platform/btoa-web.js';
import {CrdtCollectionModel} from './crdt-collection-model.js';

export async function resetStorageForTesting(key) {
  key = new FirebaseKey(key);
  let app = firebase.initializeApp({
    apiKey: key.apiKey,
    databaseURL: key.databaseUrl
  });

  let reference = firebase.database(app).ref(key.location);
  await new Promise(resolve => {
    reference.remove(resolve);
  });
  app.delete();
}

class FirebaseKey extends KeyBase {
  constructor(key) {
    super();
    let parts = key.split('://');
    this.protocol = parts[0];
    assert(this.protocol == 'firebase');
    if (parts[1]) {
      parts = parts[1].split('/');
      assert(parts[0].endsWith('.firebaseio.com'));
      this.databaseUrl = parts[0];
      this.projectId = this.databaseUrl.split('.')[0];
      this.apiKey = parts[1];
      this.location = parts.slice(2).join('/');
    } else {
      this.databaseUrl = undefined;
      this.projectId = undefined;
      this.apiKey = undefined;
      this.location = '';
    }
  }

  childKeyForHandle(id) {
    let location = '';
    if (this.location != undefined && this.location.length > 0)
      location = this.location + '/';
    location += `handles/${id}`;
    return new FirebaseKey(`${this.protocol}://${this.databaseUrl}/${this.apiKey}/${location}`);
  }

  toString() {
    if (this.databaseUrl && this.apiKey)
      return `${this.protocol}://${this.databaseUrl}/${this.apiKey}/${this.location}`;
    return `${this.protocol}://`;
  }
}

let _nextAppNameSuffix = 0;

export class FirebaseStorage {
  constructor(arcId) {
    this._arcId = arcId;
    // TODO: We need a mechanism to shut call `app.delete()` in tests,
    // otherwise the test process will not exit. Perhaps each store should
    // have a `close` function, and once all the stores for a given app
    // are closed, the app is deleted.
    this._apps = {};
  }

  async construct(id, type, keyFragment) {
    return this._join(id, type, keyFragment, false);
  }

  async connect(id, type, key) {
    return this._join(id, type, key, true);
  }

  parseStringAsKey(string) {
    return new FirebaseKey(string);
  }

  async _join(id, type, key, shouldExist) {
    key = new FirebaseKey(key);
    // TODO: is it ever going to be possible to autoconstruct new firebase datastores?
    if (key.databaseUrl == undefined || key.apiKey == undefined)
      throw new Error('Can\'t complete partial firebase keys');

    if (this._apps[key.projectId] == undefined) {
      for (let app of firebase.apps) {
        if (app.options.databaseURL == key.databaseURL) {
          this._apps[key.projectId] = app;
          break;
        }
      }
    }

    if (this._apps[key.projectId] == undefined) {
      this._apps[key.projectId] = firebase.initializeApp({
        apiKey: key.apiKey,
        databaseURL: key.databaseUrl
      }, `app${_nextAppNameSuffix++}`);
    }

    let reference = firebase.database(this._apps[key.projectId]).ref(key.location);

    let currentSnapshot;
    await reference.once('value', snapshot => currentSnapshot = snapshot);
    if (shouldExist != currentSnapshot.exists()) {
      return null;
    }

    if (!shouldExist) {
      let result = await reference.transaction(data => {
        if (data != null)
          return undefined;
        return {version: 0};
      }, undefined, false);

      if (!result.committed)
        return null;
    }

    return FirebaseStorageProvider.newProvider(type, this._arcId, id, reference, key);
  }
}

class FirebaseStorageProvider extends StorageProviderBase {
  constructor(type, arcId, id, reference, key) {
    super(type, arcId, undefined, id, key.toString());
    this._firebaseKey = key;
    this._reference = reference;

    // Resolved when local modifications complete being persisted
    // to firebase. Null when not persisting.
    this._persisting = null;
  }

  static newProvider(type, arcId, id, reference, key) {
    if (type.isCollection)
      return new FirebaseCollection(type, arcId, id, reference, key);<commit_msg>fix "id must be provided when constructing StorageProviders" exception (#1730)<commit_after>// @
// Copyright (c) 2017 Google Inc. All rights reserved.
// This code may only be used under the BSD style license found at
// http://polymer.github.io/LICENSE.txt
// Code distributed by Google as part of this project is also
// subject to an additional IP rights grant found at
// http://polymer.github.io/PATENTS.txt

import {StorageProviderBase} from './storage-provider-base.js';
import {firebase} from '../../platform/firebase-web.js';
import {assert} from '../../platform/assert-web.js';
import {KeyBase} from './key-base.js';
import {atob} from '../../platform/atob-web.js';
import {btoa} from '../../platform/btoa-web.js';
import {CrdtCollectionModel} from './crdt-collection-model.js';

export async function resetStorageForTesting(key) {
  key = new FirebaseKey(key);
  let app = firebase.initializeApp({
    apiKey: key.apiKey,
    databaseURL: key.databaseUrl
  });

  let reference = firebase.database(app).ref(key.location);
  await new Promise(resolve => {
    reference.remove(resolve);
  });
  app.delete();
}

class FirebaseKey extends KeyBase {
  constructor(key) {
    super();
    let parts = key.split('://');
    this.protocol = parts[0];
    assert(this.protocol == 'firebase');
    if (parts[1]) {
      parts = parts[1].split('/');
      assert(parts[0].endsWith('.firebaseio.com'));
      this.databaseUrl = parts[0];
      this.projectId = this.databaseUrl.split('.')[0];
      this.apiKey = parts[1];
      this.location = parts.slice(2).join('/');
    } else {
      this.databaseUrl = undefined;
      this.projectId = undefined;
      this.apiKey = undefined;
      this.location = '';
    }
  }

  childKeyForHandle(id) {
    let location = '';
    if (this.location != undefined && this.location.length > 0)
      location = this.location + '/';
    location += `handles/${id}`;
    return new FirebaseKey(`${this.protocol}://${this.databaseUrl}/${this.apiKey}/${location}`);
  }

  toString() {
    if (this.databaseUrl && this.apiKey)
      return `${this.protocol}://${this.databaseUrl}/${this.apiKey}/${this.location}`;
    return `${this.protocol}://`;
  }
}

let _nextAppNameSuffix = 0;

export class FirebaseStorage {
  constructor(arcId) {
    this._arcId = arcId;
    // TODO: We need a mechanism to shut call `app.delete()` in tests,
    // otherwise the test process will not exit. Perhaps each store should
    // have a `close` function, and once all the stores for a given app
    // are closed, the app is deleted.
    this._apps = {};
  }

  async construct(id, type, keyFragment) {
    return this._join(id, type, keyFragment, false);
  }

  async connect(id, type, key) {
    return this._join(id, type, key, true);
  }

  parseStringAsKey(string) {
    return new FirebaseKey(string);
  }

  async _join(id, type, key, shouldExist) {
    key = new FirebaseKey(key);
    // TODO: is it ever going to be possible to autoconstruct new firebase datastores?
    if (key.databaseUrl == undefined || key.apiKey == undefined)
      throw new Error('Can\'t complete partial firebase keys');

    if (this._apps[key.projectId] == undefined) {
      for (let app of firebase.apps) {
        if (app.options.databaseURL == key.databaseURL) {
          this._apps[key.projectId] = app;
          break;
        }
      }
    }

    if (this._apps[key.projectId] == undefined) {
      this._apps[key.projectId] = firebase.initializeApp({
        apiKey: key.apiKey,
        databaseURL: key.databaseUrl
      }, `app${_nextAppNameSuffix++}`);
    }

    let reference = firebase.database(this._apps[key.projectId]).ref(key.location);

    let currentSnapshot;
    await reference.once('value', snapshot => currentSnapshot = snapshot);
    if (shouldExist != currentSnapshot.exists()) {
      return null;
    }

    if (!shouldExist) {
      let result = await reference.transaction(data => {
        if (data != null)
          return undefined;
        return {version: 0};
      }, undefined, false);

      if (!result.committed)
        return null;
    }

    return FirebaseStorageProvider.newProvider(type, this._arcId, id, reference, key);
  }
}

class FirebaseStorageProvider extends StorageProviderBase {
  constructor(type, arcId, id, reference, key) {
    super(type, undefined, id, key.toString());
    this._firebaseKey = key;
    this._reference = reference;

    // Resolved when local modifications complete being persisted
    // to firebase. Null when not persisting.
    this._persisting = null;
  }

  static newProvider(type, arcId, id, reference, key) {
    if (type.isCollection)
      return new FirebaseCollection(type, arcId, id, reference, key);
{'fraction_non_alphanumeric': 0.14340671083564865, 'fraction_numerical': 0.0036332549690104724, 'mean_word_length': 3.039274924471299, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '7570925', 'n_tokens_mistral': 2860, 'n_tokens_neox': 2824, 'n_words': 747}