'use strict';

const mongo = require('mongodb');

class DbProvider {
	constructor(connection) {
		if (connection == null) {
			throw new Error('missing arguments');
		}

		this.connection = connection;
	}

	/**
	 * ドキュメントを作成します
	 *
	 * @param  {string} collectionName コレクション名
	 * @param  {object} data
	 * @return {Promise<any>}
	 */
	async createAsync(collectionName, data) {
		if (collectionName == null || data == null) {
			throw new Error('missing arguments');
		}

		return (await this.connection.collection(collectionName).insert(data)).ops[0];
	}

	/**
	 * ドキュメントを検索して項目を取得します
	 *
	 * @param  {string} collectionName
	 * @param  {object} query
	 * @param  {object} options
	 * @return {Promise<any>}
	 */
	async findAsync(collectionName, query, options) {
		if (collectionName == null || query == null) {
			throw new Error('missing arguments');
		}

		return await this.connection.collection(collectionName).findOne(query, options);
	}

	/**
	 * ドキュメントを検索して複数の項目を取得します
	 *
	 * @param  {string} collectionName
	 * @param  {object} query
	 * @param  {object} option
	 * @param  {number} limit
	 * @return {Promise<any>}
	 */
	async findArrayAsync(collectionName, query, sortOption, limit) {
		if (collectionName == null || query == null) {
			throw new Error('missing arguments');
		}

		let cursor = this.connection.collection(collectionName).find(query);

		if (limit != null) {
			cursor = cursor.limit(limit);
		}

		if (sortOption != null) {
			cursor = cursor.sort(sortOption);
		}

		return await cursor.toArray();
	}

	/**
	 * ドキュメントを更新します
	 *
	 * @param  {string} collectionName
	 * @param  {object} query
	 * @param  {object} data
	 * @param  {object} options
	 * @return {Promise<any>}
	 */
	async updateAsync(collectionName, query, data, options) {
		if (collectionName == null || query == null || data == null) {
			throw new Error('missing arguments');
		}

		options = options || {};

		return (await this.connection.collection(collectionName).update(query, options.renewal ? data : {$set: data}, options)).result;
	}

	/**
	 * ドキュメントを削除します
	 *
	 * @param  {string} collectionName
	 * @param  {object} query
	 * @return {Promise<any>}
	 */
	async removeAsync(collectionName, query) {
		if (collectionName == null || query == null) {
			throw new Error('missing arguments');
		}

		return await this.connection.collection(collectionName).remove(query);
	}

	// static methods

	/**
	 * データベースに接続します
	 *
	 * host, dbname, [authenticate]
	 * @return {Promise}
	 */
	static async connectAsync(host, dbname, authenticate) {
		if (host == null || dbname == null || authenticate == null) {
			throw new Error('missing arguments');
		}

		return await (new Promise((resolve, reject) => {
			if (host == null || dbname == null) {
				reject('missing arguments');
			}

			mongo.MongoClient.connect(`mongodb://${authenticate}@${host}/${dbname}`, (err, connection) => {
				if (err || connection == null) {
					return reject('failed to connect database');
				}

				return resolve(new DbProvider(connection));
			});
		}));
	}

	/**
	 * APIデータベースに接続します
	 */
	static async connectApidbAsync(config) {
		if (config == null) {
			throw new Error('missing arguments');
		}

		const authenticate = config.api.database.password != null ? `${config.api.database.username}:${config.api.database.password}` : config.api.database.username;
		return await DbProvider.connectAsync(
			config.api.database.host,
			config.api.database.database,
			authenticate);
	}
}
module.exports = DbProvider;

@@ -569,16 +569,19 @@
 %E3%83%A1%E3%83%B3%E3%83%88%E3%82%92%E6%A4%9C%E7%B4%A2%E3%81%97%E3%81%A6
+%E5%8D%98%E6%95%B0%E3%81%AE
 %E9%A0%85%E7%9B%AE%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%81%BE%E3%81%99
@@ -573,32 +573,32 @@
 %E6%A4%9C%E7%B4%A2%E3%81%97%E3%81%A6%E5%8D%98%E6%95%B0%E3%81%AE%E9%A0%85%E7%9B%AE%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%81%BE%E3%81%99%0A
-
 %09 *%0A%09 * @param  
@@ -1058,25 +1058,29 @@
 m  %7Bobject%7D 
-o
+sortO
 ption%0A%09 * @p
@@ -1488,32 +1488,32 @@
 rtOption);%0A%09%09%7D%0A%0A
-
 %09%09return await c
@@ -1529,24 +1529,109 @@
 rray();%0A%09%7D%0A%0A
+%09createSortOptionNatural(ascending) %7B%0A%09%09return %7B$natural: (ascending ? 1 : -1)%7D;%0A%09%7D%0A%0A
 %09/**%0A%09 * %E3%83%89%E3%82%AD%E3%83%A5

add core function