<commit_before>// Copyright IBM Corp. 2013,2016. All Rights Reserved.
// Node module: loopback-connector-postgresql
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0

'use strict';
var juggler = require('loopback-datasource-juggler');
var CreateDS = juggler.DataSource;
require('loopback-datasource-juggler/test/common.batch.js');
require('loopback-datasource-juggler/test/include.test.js');

require('./init');
var should = require('should');

var Post, db, created;

describe('lazyConnect', function() {
  it('should skip connect phase (lazyConnect = true)', function(done) {
    var dsConfig = {
      host: '127.0.0.1',
      port: 4,
      lazyConnect: true,
      debug: false,
    };
    var ds = getDS(dsConfig);

    var errTimeout = setTimeout(function() {
      done();
    }, 2000);
    ds.on('error', function(err) {
      clearTimeout(errTimeout);
      done(err);
    });
  });

  it('should report connection error (lazyConnect = false)', function(done) {
    var dsConfig = {
      host: '127.0.0.1',
      port: 4,
      lazyConnect: false,
      debug: false,
    };
    var ds = getDS(dsConfig);

    ds.on('error', function(err) {
      err.message.should.containEql('ECONNREFUSED');
      done();
    });
  });
});

var getDS = function(config) {
  var db = new CreateDS(require('../'), config);
  return db;
};

describe('postgresql connector', function() {
  before(function() {
    db = getDataSource();

    Post = db.define('PostWithBoolean', {
      title: {type: String, length: 255, index: true},
      content: {type: String},
      loc: 'GeoPoint',
      created: Date,
      approved: Boolean,
    });
    created = new Date();
  });

  it('should run migration', function(done) {
    db.automigrate('PostWithBoolean', function() {
      done();
    });
  });

  var post;
  it('should support boolean types with true value', function(done) {
    Post.create(
      {title: 'T1', content: 'C1', approved: true, created: created},
      function(err, p) {
        should.not.exists(err);
        post = p;
        Post.findById(p.id, function(err, p) {
          should.not.exists(err);
          p.should.have.property('approved', true);
          p.created.getTime().should.be.eql(created.getTime());
          done();
        });
      });
  });

  it('should preserve property `count` after query execution', function(done) {
    Post.create(
      {title: 'T10', content: 'C10'},
      function(err, p) {
        if (err) return done(err);
        post = p;
        var query = "UPDATE PostWithBoolean SET title ='T20' WHERE id=" + post.id;
        db.connector.execute(query, function(err, results) {
          results.should.have.property('count', 1);
          results.should.have.property('affectedRows', 1);
          done(err);
        });
      });
  });

  it('should support updating boolean types with false value', function(done) {
    Post.update({id: post.id}, {approved: false}, function(err) {
      should.not.exists(err);
      Post.findById(post.id, function(err, p) {
        should.not.exists(err);
        p.should.have.property('approved', false);
        done();
      });
    });
  });

  it('should support boolean types with false value', function(done) {
    Post.create(
      {title: 'T2', content: 'C2', approved: false, created: created},
      function(err, p) {
        should.not.exists(err);
        post = p;
        Post.findById(p.id, function(err, p) {
          should.not.exists(err);
          p.should.have.property('approved', false);
          done();
        });
      });
  });

  it('should support date types with eq', function(done) {
    Post.find({
      where: {created: created},
    }, function(err, posts) {
      if (err) return done(err);
      posts.length.should.eql(2);
      done();
    });
  });

  it('should support date types with between', function(done) {
    Post.find({
      where: {
        created: {
          between: [new Date(Date.now() - 5000), new Date(Date.now() + 5000)],
        }},
    }, function(err, posts) {
      if (err) return done(err);
      posts.length.should.eql(2);
      done();
    });
  });

  it('should return the model instance for upsert', function(done) {
    Post.upsert({id: post.id, title: 'T2_new', content: 'C2_new',
      approved: true}, function(err, p) {
      p.should.have.property('id', post.id);
      p.should.have.property('title', 'T2_new');
      p.should.have.property('content', 'C2_new');
      p.should.have.property('approved', true);
      done();
    });
  });

  it('should return the model instance for upsert when id is not present',
    function(done) {
      Post.upsert({title: 'T2_new', content: 'C2_new', approved: true},
        function(err, p) {
          p.should.have.property('id');
          p.should.have.property('title', 'T2_new');
          p.should.have.property('content', 'C2_new');
          p.should.have.property('approved', true);
          done();
        });
    });

  it('should escape number values to defect SQL injection in findById',
    function(done) {
      Post.findById('(SELECT 1+1)', function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should escape number values to defect SQL injection in find',
    function(done) {
      Post.find({where: {id: '(SELECT 1+1)'}}, function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should escape number values to defect SQL injection in find with gt',
    function(done) {
      Post.find({where: {id: {gt: '(SELECT 1+1)'}}}, function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should escape number values to defect SQL injection in find',
    function(done) {
      Post.find({limit: '(SELECT 1+1)'}, function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should escape number values to defect SQL injection in find with inq',
    function(done) {
      Post.find({where: {id: {inq: ['(SELECT 1+1)']}}}, function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should support GeoPoint types', function(done) {
    var GeoPoint = juggler.ModelBuilder.schemaTypes.geopoint;
    var loc = new GeoPoint({lng: 10, lat: 20});
    Post.create({title: 'T1', content: 'C1', loc: loc}, function(err, p) {
      should.not.exists(err);
      Post.findById(p.id, function(err, p) {
        should.not.exists(err);
        p.loc.lng.should.be.eql(10);
        p.loc.lat.should.be.eql(20);
        done();
      });
    });
  });

  context('regexp operator', function() {
    before(function deleteTestFixtures(done) {
      Post.destroyAll(done);
    });<commit_msg>Add tests for pattern matching operators<commit_after>// Copyright IBM Corp. 2013,2016. All Rights Reserved.
// Node module: loopback-connector-postgresql
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0

'use strict';
var juggler = require('loopback-datasource-juggler');
var CreateDS = juggler.DataSource;
require('loopback-datasource-juggler/test/common.batch.js');
require('loopback-datasource-juggler/test/include.test.js');

require('./init');
var should = require('should');

var Post, db, created;

describe('lazyConnect', function() {
  it('should skip connect phase (lazyConnect = true)', function(done) {
    var dsConfig = {
      host: '127.0.0.1',
      port: 4,
      lazyConnect: true,
      debug: false,
    };
    var ds = getDS(dsConfig);

    var errTimeout = setTimeout(function() {
      done();
    }, 2000);
    ds.on('error', function(err) {
      clearTimeout(errTimeout);
      done(err);
    });
  });

  it('should report connection error (lazyConnect = false)', function(done) {
    var dsConfig = {
      host: '127.0.0.1',
      port: 4,
      lazyConnect: false,
      debug: false,
    };
    var ds = getDS(dsConfig);

    ds.on('error', function(err) {
      err.message.should.containEql('ECONNREFUSED');
      done();
    });
  });
});

var getDS = function(config) {
  var db = new CreateDS(require('../'), config);
  return db;
};

describe('postgresql connector', function() {
  before(function() {
    db = getDataSource();

    Post = db.define('PostWithBoolean', {
      title: {type: String, length: 255, index: true},
      content: {type: String},
      loc: 'GeoPoint',
      created: Date,
      approved: Boolean,
    });
    created = new Date();
  });

  it('should run migration', function(done) {
    db.automigrate('PostWithBoolean', function() {
      done();
    });
  });

  var post;
  it('should support boolean types with true value', function(done) {
    Post.create(
      {title: 'T1', content: 'C1', approved: true, created: created},
      function(err, p) {
        should.not.exists(err);
        post = p;
        Post.findById(p.id, function(err, p) {
          should.not.exists(err);
          p.should.have.property('approved', true);
          p.created.getTime().should.be.eql(created.getTime());
          done();
        });
      });
  });

  it('should preserve property `count` after query execution', function(done) {
    Post.create(
      {title: 'T10', content: 'C10'},
      function(err, p) {
        if (err) return done(err);
        post = p;
        var query = "UPDATE PostWithBoolean SET title ='T20' WHERE id=" + post.id;
        db.connector.execute(query, function(err, results) {
          results.should.have.property('count', 1);
          results.should.have.property('affectedRows', 1);
          done(err);
        });
      });
  });

  it('should support updating boolean types with false value', function(done) {
    Post.update({id: post.id}, {approved: false}, function(err) {
      should.not.exists(err);
      Post.findById(post.id, function(err, p) {
        should.not.exists(err);
        p.should.have.property('approved', false);
        done();
      });
    });
  });

  it('should support boolean types with false value', function(done) {
    Post.create(
      {title: 'T2', content: 'C2', approved: false, created: created},
      function(err, p) {
        should.not.exists(err);
        post = p;
        Post.findById(p.id, function(err, p) {
          should.not.exists(err);
          p.should.have.property('approved', false);
          done();
        });
      });
  });

  it('should support date types with eq', function(done) {
    Post.find({
      where: {created: created},
    }, function(err, posts) {
      if (err) return done(err);
      posts.length.should.eql(2);
      done();
    });
  });

  it('should support date types with between', function(done) {
    Post.find({
      where: {
        created: {
          between: [new Date(Date.now() - 5000), new Date(Date.now() + 5000)],
        }},
    }, function(err, posts) {
      if (err) return done(err);
      posts.length.should.eql(2);
      done();
    });
  });

  it('should return the model instance for upsert', function(done) {
    Post.upsert({id: post.id, title: 'T2_new', content: 'C2_new',
      approved: true}, function(err, p) {
      p.should.have.property('id', post.id);
      p.should.have.property('title', 'T2_new');
      p.should.have.property('content', 'C2_new');
      p.should.have.property('approved', true);
      done();
    });
  });

  it('should return the model instance for upsert when id is not present',
    function(done) {
      Post.upsert({title: 'T2_new', content: 'C2_new', approved: true},
        function(err, p) {
          p.should.have.property('id');
          p.should.have.property('title', 'T2_new');
          p.should.have.property('content', 'C2_new');
          p.should.have.property('approved', true);
          done();
        });
    });

  it('should escape number values to defect SQL injection in findById',
    function(done) {
      Post.findById('(SELECT 1+1)', function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should escape number values to defect SQL injection in find',
    function(done) {
      Post.find({where: {id: '(SELECT 1+1)'}}, function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should escape number values to defect SQL injection in find with gt',
    function(done) {
      Post.find({where: {id: {gt: '(SELECT 1+1)'}}}, function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should escape number values to defect SQL injection in find',
    function(done) {
      Post.find({limit: '(SELECT 1+1)'}, function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should escape number values to defect SQL injection in find with inq',
    function(done) {
      Post.find({where: {id: {inq: ['(SELECT 1+1)']}}}, function(err, p) {
        should.exists(err);
        done();
      });
    });

  it('should support GeoPoint types', function(done) {
    var GeoPoint = juggler.ModelBuilder.schemaTypes.geopoint;
    var loc = new GeoPoint({lng: 10, lat: 20});
    Post.create({title: 'T1', content: 'C1', loc: loc}, function(err, p) {
      should.not.exists(err);
      Post.findById(p.id, function(err, p) {
        should.not.exists(err);
        p.loc.lng.should.be.eql(10);
        p.loc.lat.should.be.eql(20);
        done();
      });
    });
  });

  context('pattern matching operators', function() {
    before(function deleteTestFixtures(done) {
      Post.destroyAll(done);
    });
    before(function createTextFixtures(done) {
      Post.create([{
        title: 't1',
        content: 'T1_TestCase',
      }, {
        title: 't2',
        content: 'T2_TheOtherCase',
      }], done);
    });
    after(function deleteTestFixtures(done) {
      Post.destroyAll(done);
    });

    it('should support case sensitive queries using like',
      function(done) {
        Post.find({where: {content: {like: '%TestCase%'}}},
          function(err, posts) {
            should.not.exists(err);
            posts.length.should.equal(1);
            posts[0].content.should.equal('T1_TestCase');
            done();
          });
      });

    it('should not support case insensitive queries using like',
      function(done) {
        Post.find({where: {content: {like: '%tesTcasE%'}}},
          function(err, posts) {
            should.not.exists(err);
            posts.length.should.equal(0);
            done();
          });
      });

    it('should support like for no match', function(done) {
      Post.find({where: {content: {like: '%TestXase%'}}},
        function(err, posts) {
          should.not.exists(err);
          posts.length.should.equal(0);
          done();
        });
    });

    it('should support negative case sensitive queries using nlike',
      function(done) {
        Post.find({where: {content: {nlike: '%Case%'}}},
          function(err, posts) {
            should.not.exists(err);
            posts.length.should.equal(0);
            done();
          });
      });

    it('should not support negative case insensitive queries using nlike',
      function(done) {
        Post.find({where: {content: {nlike: '%casE%'}}},
          function(err, posts) {
            should.not.exists(err);
            posts.length.should.equal(2);
            done();
          });
      });

    it('should support nlike for no match', function(done) {
      Post.find({where: {content: {nlike: '%TestXase%'}}},
        function(err, posts) {
          should.not.exists(err);
          posts.length.should.equal(2);
          done();
        });
    });

    it('should support case insensitive queries using ilike', function(done) {
      Post.find({where: {content: {ilike: '%tesTcasE%'}}},
        function(err, posts) {
          should.not.exist(err);
          posts.length.should.equal(1);
          posts[0].content.should.equal('T1_TestCase');
          done();
        });
    });

    it('should support ilike for no match', function(done) {
      Post.find({where: {content: {ilike: '%tesTxasE%'}}},
        function(err, posts) {
          should.not.exists(err);
          posts.length.should.equal(0);
          done();
        });
    });

    it('should support negative case insensitive queries using nilike',
      function(done) {
        Post.find({where: {content: {nilike: '%casE%'}}},
          function(err, posts) {
            should.not.exist(err);
            posts.length.should.equal(0);
            done();
          });
      });

    it('should support nilike for no match', function(done) {
      Post.find({where: {content: {nilike: '%tesTxasE%'}}},
        function(err, posts) {
          should.not.exists(err);
          posts.length.should.equal(2);
          done();
        });
    });
  });

  context('regexp operator', function() {
    before(function deleteTestFixtures(done) {
      Post.destroyAll(done);
    });
{'fraction_non_alphanumeric': 0.16742401888462674, 'fraction_numerical': 0.010858660371791088, 'mean_word_length': 2.455546492659054, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, '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': '2191948', 'n_tokens_mistral': 5421, 'n_tokens_neox': 5227, 'n_words': 1198}