<commit_before>'use strict';

var _ = require('lodash');
var chai = require('chai');
var expect = chai.expect;

var Database = require('../../lib/database');
var FakeAdapter = require('../fakes/adapter');

var db,
  adapter,
  Article,
  User,
  user,
  articleObjects;

var withAuthor = function(authorId, attrs) {
  var authorAttr = _.object([['author_id', authorId]]);
  return _.extend(attrs, authorAttr);
};

describe('Model.hasMany', function() {
  beforeEach(function() {
    adapter = FakeAdapter.create({});
    db = Database.create({ adapter: adapter });

    var Model = db.Model;
    var hasMany = Model.hasMany;
    var attr = Model.attr;

    Article = db.Model.extend({
      title: attr(),
      authorId: attr('author_id') // TODO: replace with belongsTo
    });
    User = db.Model.extend({
      username: attr(),
      articles: hasMany(Article, { inverse: 'author' })
    });

    // name the classes as late as possible to ensure we're not locking in
    // anything based on the class name. all information should be computed
    // from property names or delayed until the time of access to the db.
    Article.reopenClass({ __name__: 'Article' });
    User.reopenClass({ __name__: 'User' });
  });

  beforeEach(function() {
    user = User.create({ id: 1 });
    articleObjects = user.articleObjects;
  });

  beforeEach(function() {
    adapter.intercept(/select.*from "users"/i, {
      fields: ['id', 'username'],
      rows: [{ id: 1, username: 'wbyoung' }]
    });
    adapter.intercept(/select.*from "articles"/i, {
      fields: ['id', 'title'],
      rows: [withAuthor(1, { id: 1, title: 'Existing Article' })]
    });
  });

  it('has related methods', function() {
    expect(User.__class__.prototype).to.have.ownProperty('articles');
    expect(user).to.have.property('articleObjects');
    expect(user).to.respondTo('createArticle');
    expect(user).to.respondTo('createArticle');
    expect(user).to.respondTo('addArticle');
    expect(user).to.respondTo('addArticles');
    expect(user).to.respondTo('removeArticle');
    expect(user).to.respondTo('removeArticles');
    expect(user).to.respondTo('clearArticles');
  });

  describe('pre-fetch', function() {
    it('executes multiple queries', function(done) {
      User.objects.with('articles').fetch().then(function() {
        expect(adapter.executedSQL()).to.eql([
          ['SELECT * FROM "users"', []],
          ['SELECT * FROM "articles" WHERE "author_id" = ?', [1]]
        ]);
      })
      .done(done, done);
    });

    it('caches related objects', function(done) {
      User.objects.with('articles').fetch().get('0').then(function(foundUser) {
        expect(foundUser.id).to.eql(1);
        expect(foundUser.username).to.eql('wbyoung');
        expect(foundUser.articles).to.eql([
          Article.create({ id: 1, title: 'Existing Article', authorId: 1 })
        ]);
      })
      .done(done, done);
    });

    it('works with multiple users each authoring multiple articles', function(done) {
      adapter.intercept(/select.*from "users".*order by "id"/i, {
        fields: ['id', 'username'],
        rows: [
          { id: 1, username: 'wbyoung' },
          { id: 2, username: 'kate' },
          { id: 4, username: 'sam' },
        ]
      });
      adapter.intercept(/select.*from "articles"/i, {
        fields: ['id', 'title', 'author_id'],
        rows: [
          withAuthor(1, { id: 3, title: 'Announcing Azul' }),
          withAuthor(1, { id: 5, title: 'Node.js ORM' }),
          withAuthor(2, { id: 9, title: 'Delicious Pancakes' }),
          withAuthor(2, { id: 8, title: 'Awesome Margaritas' }),
          withAuthor(2, { id: 5, title: 'Tasty <NAME>' }),
          withAuthor(4, { id: 6, title: 'The Bipartisan System' }),
        ]
      });

      User.objects.with('articles').orderBy('id').fetch().then(function(users) {
        expect(users[0].username).to.eql('wbyoung');
        expect(users[1].username).to.eql('kate');
        expect(users[2].username).to.eql('sam');
        console.log(users[0].articles)
        expect(_.map(users[0].articles, 'title')).to.eql([
          'Announcing Azul', 'Node.js ORM'
        ]);
        expect(_.map(users[1].articles, 'title')).to.eql([<commit_msg>Removed console.log.<commit_after>'use strict';

var _ = require('lodash');
var chai = require('chai');
var expect = chai.expect;

var Database = require('../../lib/database');
var FakeAdapter = require('../fakes/adapter');

var db,
  adapter,
  Article,
  User,
  user,
  articleObjects;

var withAuthor = function(authorId, attrs) {
  var authorAttr = _.object([['author_id', authorId]]);
  return _.extend(attrs, authorAttr);
};

describe('Model.hasMany', function() {
  beforeEach(function() {
    adapter = FakeAdapter.create({});
    db = Database.create({ adapter: adapter });

    var Model = db.Model;
    var hasMany = Model.hasMany;
    var attr = Model.attr;

    Article = db.Model.extend({
      title: attr(),
      authorId: attr('author_id') // TODO: replace with belongsTo
    });
    User = db.Model.extend({
      username: attr(),
      articles: hasMany(Article, { inverse: 'author' })
    });

    // name the classes as late as possible to ensure we're not locking in
    // anything based on the class name. all information should be computed
    // from property names or delayed until the time of access to the db.
    Article.reopenClass({ __name__: 'Article' });
    User.reopenClass({ __name__: 'User' });
  });

  beforeEach(function() {
    user = User.create({ id: 1 });
    articleObjects = user.articleObjects;
  });

  beforeEach(function() {
    adapter.intercept(/select.*from "users"/i, {
      fields: ['id', 'username'],
      rows: [{ id: 1, username: 'wbyoung' }]
    });
    adapter.intercept(/select.*from "articles"/i, {
      fields: ['id', 'title'],
      rows: [withAuthor(1, { id: 1, title: 'Existing Article' })]
    });
  });

  it('has related methods', function() {
    expect(User.__class__.prototype).to.have.ownProperty('articles');
    expect(user).to.have.property('articleObjects');
    expect(user).to.respondTo('createArticle');
    expect(user).to.respondTo('createArticle');
    expect(user).to.respondTo('addArticle');
    expect(user).to.respondTo('addArticles');
    expect(user).to.respondTo('removeArticle');
    expect(user).to.respondTo('removeArticles');
    expect(user).to.respondTo('clearArticles');
  });

  describe('pre-fetch', function() {
    it('executes multiple queries', function(done) {
      User.objects.with('articles').fetch().then(function() {
        expect(adapter.executedSQL()).to.eql([
          ['SELECT * FROM "users"', []],
          ['SELECT * FROM "articles" WHERE "author_id" = ?', [1]]
        ]);
      })
      .done(done, done);
    });

    it('caches related objects', function(done) {
      User.objects.with('articles').fetch().get('0').then(function(foundUser) {
        expect(foundUser.id).to.eql(1);
        expect(foundUser.username).to.eql('wbyoung');
        expect(foundUser.articles).to.eql([
          Article.create({ id: 1, title: 'Existing Article', authorId: 1 })
        ]);
      })
      .done(done, done);
    });

    it('works with multiple users each authoring multiple articles', function(done) {
      adapter.intercept(/select.*from "users".*order by "id"/i, {
        fields: ['id', 'username'],
        rows: [
          { id: 1, username: 'wbyoung' },
          { id: 2, username: 'kate' },
          { id: 4, username: 'sam' },
        ]
      });
      adapter.intercept(/select.*from "articles"/i, {
        fields: ['id', 'title', 'author_id'],
        rows: [
          withAuthor(1, { id: 3, title: 'Announcing Azul' }),
          withAuthor(1, { id: 5, title: 'Node.js ORM' }),
          withAuthor(2, { id: 9, title: 'Delicious Pancakes' }),
          withAuthor(2, { id: 8, title: 'Awesome Margaritas' }),
          withAuthor(2, { id: 5, title: 'Tasty Kale Salad' }),
          withAuthor(4, { id: 6, title: 'The Bipartisan System' }),
        ]
      });

      User.objects.with('articles').orderBy('id').fetch().then(function(users) {
        expect(users[0].username).to.eql('wbyoung');
        expect(users[1].username).to.eql('kate');
        expect(users[2].username).to.eql('sam');
        expect(_.map(users[0].articles, 'title')).to.eql([
          'Announcing Azul', 'Node.js ORM'
        ]);
        expect(_.map(users[1].articles, 'title')).to.eql([
{'fraction_non_alphanumeric': 0.1833254381809569, 'fraction_numerical': 0.006987209853150165, 'mean_word_length': 2.924256505576208, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, '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': '647495', 'n_tokens_mistral': 2742, 'n_tokens_neox': 2645, 'n_words': 558}