meadow-connection-mongodb 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -3
- package/scripts/mongodb-test-db.sh +98 -0
- package/source/Meadow-Connection-MongoDB.js +15 -118
- package/source/Meadow-Schema-MongoDB.js +170 -0
- package/test/MongoDB_tests.js +465 -19
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meadow-connection-mongodb",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Meadow MongoDB Connection Plugin",
|
|
5
5
|
"main": "source/Meadow-Connection-MongoDB.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"coverage": "npx quack coverage",
|
|
8
|
-
"test": "npx quack test"
|
|
8
|
+
"test": "npx quack test",
|
|
9
|
+
"docker-mongodb-start": "bash ./scripts/mongodb-test-db.sh start",
|
|
10
|
+
"docker-mongodb-stop": "bash ./scripts/mongodb-test-db.sh stop",
|
|
11
|
+
"docker-mongodb-status": "bash ./scripts/mongodb-test-db.sh status",
|
|
12
|
+
"test-docker": "bash ./scripts/mongodb-test-db.sh start && npm test"
|
|
9
13
|
},
|
|
10
14
|
"mocha": {
|
|
11
15
|
"diff": true,
|
|
@@ -15,7 +19,7 @@
|
|
|
15
19
|
"package": "./package.json",
|
|
16
20
|
"reporter": "spec",
|
|
17
21
|
"slow": "75",
|
|
18
|
-
"timeout": "
|
|
22
|
+
"timeout": "10000",
|
|
19
23
|
"ui": "tdd",
|
|
20
24
|
"watch-files": [
|
|
21
25
|
"source/**/*.js",
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# MongoDB Test Database Management Script for meadow-connection-mongodb
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# ./scripts/mongodb-test-db.sh start - Start MongoDB container and wait for readiness
|
|
6
|
+
# ./scripts/mongodb-test-db.sh stop - Stop and remove the container
|
|
7
|
+
# ./scripts/mongodb-test-db.sh status - Check if the container is running
|
|
8
|
+
#
|
|
9
|
+
# The container settings match the test configuration in
|
|
10
|
+
# test/MongoDB_tests.js:
|
|
11
|
+
# Host: 127.0.0.1, Port: 27117, Database: meadow_conn_test
|
|
12
|
+
|
|
13
|
+
CONTAINER_NAME="meadow-conn-mongodb-test"
|
|
14
|
+
MONGODB_PORT="27117"
|
|
15
|
+
MONGODB_IMAGE="mongo:7"
|
|
16
|
+
|
|
17
|
+
start_mongodb() {
|
|
18
|
+
# Check if container already exists
|
|
19
|
+
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
20
|
+
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
21
|
+
echo "MongoDB test container is already running."
|
|
22
|
+
return 0
|
|
23
|
+
else
|
|
24
|
+
echo "Removing stopped container..."
|
|
25
|
+
docker rm "${CONTAINER_NAME}" > /dev/null 2>&1
|
|
26
|
+
fi
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
echo "Starting MongoDB test container..."
|
|
30
|
+
docker run -d \
|
|
31
|
+
--name "${CONTAINER_NAME}" \
|
|
32
|
+
-p "${MONGODB_PORT}:27017" \
|
|
33
|
+
"${MONGODB_IMAGE}"
|
|
34
|
+
|
|
35
|
+
if [ $? -ne 0 ]; then
|
|
36
|
+
echo "ERROR: Failed to start MongoDB container."
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
echo "Waiting for MongoDB to be ready..."
|
|
41
|
+
RETRIES=30
|
|
42
|
+
until docker exec "${CONTAINER_NAME}" mongosh --eval "db.adminCommand('ping')" > /dev/null 2>&1; do
|
|
43
|
+
RETRIES=$((RETRIES - 1))
|
|
44
|
+
if [ $RETRIES -le 0 ]; then
|
|
45
|
+
echo "ERROR: MongoDB failed to become ready in time."
|
|
46
|
+
docker logs "${CONTAINER_NAME}" 2>&1 | tail -20
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
echo " ...waiting (${RETRIES} retries left)"
|
|
50
|
+
sleep 2
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
echo ""
|
|
54
|
+
echo "MongoDB test database is ready!"
|
|
55
|
+
echo " Container: ${CONTAINER_NAME}"
|
|
56
|
+
echo " Host: 127.0.0.1:${MONGODB_PORT}"
|
|
57
|
+
echo " Database: meadow_conn_test"
|
|
58
|
+
echo ""
|
|
59
|
+
echo "Run tests with: npm test"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
stop_mongodb() {
|
|
63
|
+
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
64
|
+
echo "Stopping and removing MongoDB test container..."
|
|
65
|
+
docker stop "${CONTAINER_NAME}" > /dev/null 2>&1
|
|
66
|
+
docker rm "${CONTAINER_NAME}" > /dev/null 2>&1
|
|
67
|
+
echo "MongoDB test container removed."
|
|
68
|
+
else
|
|
69
|
+
echo "No MongoDB test container found."
|
|
70
|
+
fi
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
status_mongodb() {
|
|
74
|
+
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
75
|
+
echo "MongoDB test container is running."
|
|
76
|
+
docker ps --filter "name=${CONTAINER_NAME}" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
|
77
|
+
elif docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
78
|
+
echo "MongoDB test container exists but is stopped."
|
|
79
|
+
else
|
|
80
|
+
echo "MongoDB test container is not running."
|
|
81
|
+
fi
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
case "${1}" in
|
|
85
|
+
start)
|
|
86
|
+
start_mongodb
|
|
87
|
+
;;
|
|
88
|
+
stop)
|
|
89
|
+
stop_mongodb
|
|
90
|
+
;;
|
|
91
|
+
status)
|
|
92
|
+
status_mongodb
|
|
93
|
+
;;
|
|
94
|
+
*)
|
|
95
|
+
echo "Usage: $0 {start|stop|status}"
|
|
96
|
+
exit 1
|
|
97
|
+
;;
|
|
98
|
+
esac
|
|
@@ -6,6 +6,8 @@ const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
|
6
6
|
|
|
7
7
|
const { MongoClient } = require('mongodb');
|
|
8
8
|
|
|
9
|
+
const libMeadowSchemaMongoDB = require('./Meadow-Schema-MongoDB.js');
|
|
10
|
+
|
|
9
11
|
class MeadowConnectionMongoDB extends libFableServiceProviderBase
|
|
10
12
|
{
|
|
11
13
|
constructor(pFable, pManifest, pServiceHash)
|
|
@@ -66,12 +68,20 @@ class MeadowConnectionMongoDB extends libFableServiceProviderBase
|
|
|
66
68
|
this._Database = false;
|
|
67
69
|
this.connected = false;
|
|
68
70
|
|
|
71
|
+
// Schema provider handles DDL operations (create, drop, index, etc.)
|
|
72
|
+
this._SchemaProvider = new libMeadowSchemaMongoDB(this.fable, this.options, `${this.Hash}-Schema`);
|
|
73
|
+
|
|
69
74
|
if (this.options.MeadowConnectionMongoDBAutoConnect)
|
|
70
75
|
{
|
|
71
76
|
this.connect();
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
|
|
80
|
+
get schemaProvider()
|
|
81
|
+
{
|
|
82
|
+
return this._SchemaProvider;
|
|
83
|
+
}
|
|
84
|
+
|
|
75
85
|
/**
|
|
76
86
|
* Build the MongoDB connection URI from options.
|
|
77
87
|
*/
|
|
@@ -96,136 +106,22 @@ class MeadowConnectionMongoDB extends libFableServiceProviderBase
|
|
|
96
106
|
|
|
97
107
|
generateDropTableStatement(pTableName)
|
|
98
108
|
{
|
|
99
|
-
|
|
100
|
-
return { operation: 'drop', collection: pTableName };
|
|
109
|
+
return this._SchemaProvider.generateDropTableStatement(pTableName);
|
|
101
110
|
}
|
|
102
111
|
|
|
103
112
|
generateCreateTableStatement(pMeadowTableSchema)
|
|
104
113
|
{
|
|
105
|
-
this.
|
|
106
|
-
|
|
107
|
-
let tmpDescriptor = {
|
|
108
|
-
operation: 'createCollection',
|
|
109
|
-
collection: pMeadowTableSchema.TableName,
|
|
110
|
-
indexes: []
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
for (let j = 0; j < pMeadowTableSchema.Columns.length; j++)
|
|
114
|
-
{
|
|
115
|
-
let tmpColumn = pMeadowTableSchema.Columns[j];
|
|
116
|
-
|
|
117
|
-
switch (tmpColumn.DataType)
|
|
118
|
-
{
|
|
119
|
-
case 'ID':
|
|
120
|
-
// AutoIdentity field gets a unique ascending index
|
|
121
|
-
tmpDescriptor.indexes.push(
|
|
122
|
-
{
|
|
123
|
-
key: { [tmpColumn.Column]: 1 },
|
|
124
|
-
unique: true,
|
|
125
|
-
name: `idx_${tmpColumn.Column}_unique`
|
|
126
|
-
});
|
|
127
|
-
break;
|
|
128
|
-
case 'GUID':
|
|
129
|
-
// GUID field gets a unique index
|
|
130
|
-
tmpDescriptor.indexes.push(
|
|
131
|
-
{
|
|
132
|
-
key: { [tmpColumn.Column]: 1 },
|
|
133
|
-
unique: true,
|
|
134
|
-
name: `idx_${tmpColumn.Column}_unique`
|
|
135
|
-
});
|
|
136
|
-
break;
|
|
137
|
-
case 'ForeignKey':
|
|
138
|
-
// Foreign key gets an index for lookups
|
|
139
|
-
tmpDescriptor.indexes.push(
|
|
140
|
-
{
|
|
141
|
-
key: { [tmpColumn.Column]: 1 },
|
|
142
|
-
name: `idx_${tmpColumn.Column}`
|
|
143
|
-
});
|
|
144
|
-
break;
|
|
145
|
-
default:
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return tmpDescriptor;
|
|
114
|
+
return this._SchemaProvider.generateCreateTableStatement(pMeadowTableSchema);
|
|
151
115
|
}
|
|
152
116
|
|
|
153
117
|
createTables(pMeadowSchema, fCallback)
|
|
154
118
|
{
|
|
155
|
-
this.
|
|
156
|
-
(pTable, fCreateComplete) =>
|
|
157
|
-
{
|
|
158
|
-
return this.createTable(pTable, fCreateComplete);
|
|
159
|
-
},
|
|
160
|
-
(pCreateError) =>
|
|
161
|
-
{
|
|
162
|
-
if (pCreateError)
|
|
163
|
-
{
|
|
164
|
-
this.log.error(`Meadow-MongoDB Error creating collections from Schema: ${pCreateError}`, pCreateError);
|
|
165
|
-
}
|
|
166
|
-
this.log.info('Done creating collections!');
|
|
167
|
-
return fCallback(pCreateError);
|
|
168
|
-
});
|
|
119
|
+
return this._SchemaProvider.createTables(pMeadowSchema, fCallback);
|
|
169
120
|
}
|
|
170
121
|
|
|
171
122
|
createTable(pMeadowTableSchema, fCallback)
|
|
172
123
|
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (!this._Database)
|
|
176
|
-
{
|
|
177
|
-
this.log.error(`Meadow-MongoDB CREATE COLLECTION ${tmpDescriptor.collection} failed: not connected.`);
|
|
178
|
-
return fCallback(new Error('Not connected to MongoDB'));
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Create collection (ignore error if it already exists)
|
|
182
|
-
this._Database.createCollection(tmpDescriptor.collection)
|
|
183
|
-
.then(() =>
|
|
184
|
-
{
|
|
185
|
-
this.log.info(`Meadow-MongoDB collection ${tmpDescriptor.collection} created or already exists.`);
|
|
186
|
-
|
|
187
|
-
// Create indexes if any
|
|
188
|
-
if (tmpDescriptor.indexes.length > 0)
|
|
189
|
-
{
|
|
190
|
-
let tmpCollection = this._Database.collection(tmpDescriptor.collection);
|
|
191
|
-
return tmpCollection.createIndexes(tmpDescriptor.indexes);
|
|
192
|
-
}
|
|
193
|
-
})
|
|
194
|
-
.then(() =>
|
|
195
|
-
{
|
|
196
|
-
this.log.info(`Meadow-MongoDB indexes for ${tmpDescriptor.collection} created successfully.`);
|
|
197
|
-
return fCallback();
|
|
198
|
-
})
|
|
199
|
-
.catch((pError) =>
|
|
200
|
-
{
|
|
201
|
-
// 48 = NamespaceExists (collection already exists)
|
|
202
|
-
if (pError.code === 48)
|
|
203
|
-
{
|
|
204
|
-
this.log.warn(`Meadow-MongoDB collection ${tmpDescriptor.collection} already existed.`);
|
|
205
|
-
|
|
206
|
-
// Still try to create indexes
|
|
207
|
-
if (tmpDescriptor.indexes.length > 0)
|
|
208
|
-
{
|
|
209
|
-
let tmpCollection = this._Database.collection(tmpDescriptor.collection);
|
|
210
|
-
tmpCollection.createIndexes(tmpDescriptor.indexes)
|
|
211
|
-
.then(() => fCallback())
|
|
212
|
-
.catch((pIndexError) =>
|
|
213
|
-
{
|
|
214
|
-
this.log.warn(`Meadow-MongoDB index creation for ${tmpDescriptor.collection}: ${pIndexError.message}`);
|
|
215
|
-
return fCallback();
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
else
|
|
219
|
-
{
|
|
220
|
-
return fCallback();
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
else
|
|
224
|
-
{
|
|
225
|
-
this.log.error(`Meadow-MongoDB CREATE COLLECTION ${tmpDescriptor.collection} failed!`, pError);
|
|
226
|
-
return fCallback(pError);
|
|
227
|
-
}
|
|
228
|
-
});
|
|
124
|
+
return this._SchemaProvider.createTable(pMeadowTableSchema, fCallback);
|
|
229
125
|
}
|
|
230
126
|
|
|
231
127
|
connect()
|
|
@@ -248,6 +144,7 @@ class MeadowConnectionMongoDB extends libFableServiceProviderBase
|
|
|
248
144
|
this._Client = new MongoClient(tmpURI, tmpOptions);
|
|
249
145
|
this._Database = this._Client.db(this.options.MongoDB.database);
|
|
250
146
|
this.connected = true;
|
|
147
|
+
this._SchemaProvider.setDatabase(this._Database);
|
|
251
148
|
}
|
|
252
149
|
|
|
253
150
|
connectAsync(fCallback)
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow MongoDB Schema Provider
|
|
3
|
+
*
|
|
4
|
+
* Handles collection creation, dropping, and schema generation for MongoDB.
|
|
5
|
+
* Separated from the connection provider to allow independent extension
|
|
6
|
+
* for indexing and other schema operations.
|
|
7
|
+
*
|
|
8
|
+
* @author Steven Velozo <steven@velozo.com>
|
|
9
|
+
*/
|
|
10
|
+
const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
11
|
+
|
|
12
|
+
class MeadowSchemaMongoDB extends libFableServiceProviderBase
|
|
13
|
+
{
|
|
14
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
15
|
+
{
|
|
16
|
+
super(pFable, pOptions, pServiceHash);
|
|
17
|
+
|
|
18
|
+
this.serviceType = 'MeadowSchemaMongoDB';
|
|
19
|
+
|
|
20
|
+
// Reference to the MongoDB database instance, set by the connection provider
|
|
21
|
+
this._Database = false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Set the database reference for executing schema operations.
|
|
26
|
+
* @param {object} pDatabase - MongoDB Db instance
|
|
27
|
+
* @returns {MeadowSchemaMongoDB} this (for chaining)
|
|
28
|
+
*/
|
|
29
|
+
setDatabase(pDatabase)
|
|
30
|
+
{
|
|
31
|
+
this._Database = pDatabase;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
generateDropTableStatement(pTableName)
|
|
36
|
+
{
|
|
37
|
+
// Returns a descriptor; the actual drop uses the MongoDB driver
|
|
38
|
+
return { operation: 'drop', collection: pTableName };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
generateCreateTableStatement(pMeadowTableSchema)
|
|
42
|
+
{
|
|
43
|
+
this.log.info(`--> Building the collection creation descriptor for ${pMeadowTableSchema.TableName} ...`);
|
|
44
|
+
|
|
45
|
+
let tmpDescriptor = {
|
|
46
|
+
operation: 'createCollection',
|
|
47
|
+
collection: pMeadowTableSchema.TableName,
|
|
48
|
+
indexes: []
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
for (let j = 0; j < pMeadowTableSchema.Columns.length; j++)
|
|
52
|
+
{
|
|
53
|
+
let tmpColumn = pMeadowTableSchema.Columns[j];
|
|
54
|
+
|
|
55
|
+
switch (tmpColumn.DataType)
|
|
56
|
+
{
|
|
57
|
+
case 'ID':
|
|
58
|
+
// AutoIdentity field gets a unique ascending index
|
|
59
|
+
tmpDescriptor.indexes.push(
|
|
60
|
+
{
|
|
61
|
+
key: { [tmpColumn.Column]: 1 },
|
|
62
|
+
unique: true,
|
|
63
|
+
name: `idx_${tmpColumn.Column}_unique`
|
|
64
|
+
});
|
|
65
|
+
break;
|
|
66
|
+
case 'GUID':
|
|
67
|
+
// GUID field gets a unique index
|
|
68
|
+
tmpDescriptor.indexes.push(
|
|
69
|
+
{
|
|
70
|
+
key: { [tmpColumn.Column]: 1 },
|
|
71
|
+
unique: true,
|
|
72
|
+
name: `idx_${tmpColumn.Column}_unique`
|
|
73
|
+
});
|
|
74
|
+
break;
|
|
75
|
+
case 'ForeignKey':
|
|
76
|
+
// Foreign key gets an index for lookups
|
|
77
|
+
tmpDescriptor.indexes.push(
|
|
78
|
+
{
|
|
79
|
+
key: { [tmpColumn.Column]: 1 },
|
|
80
|
+
name: `idx_${tmpColumn.Column}`
|
|
81
|
+
});
|
|
82
|
+
break;
|
|
83
|
+
default:
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return tmpDescriptor;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
createTables(pMeadowSchema, fCallback)
|
|
92
|
+
{
|
|
93
|
+
this.fable.Utility.eachLimit(pMeadowSchema.Tables, 1,
|
|
94
|
+
(pTable, fCreateComplete) =>
|
|
95
|
+
{
|
|
96
|
+
return this.createTable(pTable, fCreateComplete);
|
|
97
|
+
},
|
|
98
|
+
(pCreateError) =>
|
|
99
|
+
{
|
|
100
|
+
if (pCreateError)
|
|
101
|
+
{
|
|
102
|
+
this.log.error(`Meadow-MongoDB Error creating collections from Schema: ${pCreateError}`, pCreateError);
|
|
103
|
+
}
|
|
104
|
+
this.log.info('Done creating collections!');
|
|
105
|
+
return fCallback(pCreateError);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
createTable(pMeadowTableSchema, fCallback)
|
|
110
|
+
{
|
|
111
|
+
let tmpDescriptor = this.generateCreateTableStatement(pMeadowTableSchema);
|
|
112
|
+
|
|
113
|
+
if (!this._Database)
|
|
114
|
+
{
|
|
115
|
+
this.log.error(`Meadow-MongoDB CREATE COLLECTION ${tmpDescriptor.collection} failed: not connected.`);
|
|
116
|
+
return fCallback(new Error('Not connected to MongoDB'));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Create collection (ignore error if it already exists)
|
|
120
|
+
this._Database.createCollection(tmpDescriptor.collection)
|
|
121
|
+
.then(() =>
|
|
122
|
+
{
|
|
123
|
+
this.log.info(`Meadow-MongoDB collection ${tmpDescriptor.collection} created or already exists.`);
|
|
124
|
+
|
|
125
|
+
// Create indexes if any
|
|
126
|
+
if (tmpDescriptor.indexes.length > 0)
|
|
127
|
+
{
|
|
128
|
+
let tmpCollection = this._Database.collection(tmpDescriptor.collection);
|
|
129
|
+
return tmpCollection.createIndexes(tmpDescriptor.indexes);
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
.then(() =>
|
|
133
|
+
{
|
|
134
|
+
this.log.info(`Meadow-MongoDB indexes for ${tmpDescriptor.collection} created successfully.`);
|
|
135
|
+
return fCallback();
|
|
136
|
+
})
|
|
137
|
+
.catch((pError) =>
|
|
138
|
+
{
|
|
139
|
+
// 48 = NamespaceExists (collection already exists)
|
|
140
|
+
if (pError.code === 48)
|
|
141
|
+
{
|
|
142
|
+
this.log.warn(`Meadow-MongoDB collection ${tmpDescriptor.collection} already existed.`);
|
|
143
|
+
|
|
144
|
+
// Still try to create indexes
|
|
145
|
+
if (tmpDescriptor.indexes.length > 0)
|
|
146
|
+
{
|
|
147
|
+
let tmpCollection = this._Database.collection(tmpDescriptor.collection);
|
|
148
|
+
tmpCollection.createIndexes(tmpDescriptor.indexes)
|
|
149
|
+
.then(() => fCallback())
|
|
150
|
+
.catch((pIndexError) =>
|
|
151
|
+
{
|
|
152
|
+
this.log.warn(`Meadow-MongoDB index creation for ${tmpDescriptor.collection}: ${pIndexError.message}`);
|
|
153
|
+
return fCallback();
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
else
|
|
157
|
+
{
|
|
158
|
+
return fCallback();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else
|
|
162
|
+
{
|
|
163
|
+
this.log.error(`Meadow-MongoDB CREATE COLLECTION ${tmpDescriptor.collection} failed!`, pError);
|
|
164
|
+
return fCallback(pError);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = MeadowSchemaMongoDB;
|
package/test/MongoDB_tests.js
CHANGED
|
@@ -32,14 +32,40 @@ const _FableConfig = (
|
|
|
32
32
|
"MongoDB":
|
|
33
33
|
{
|
|
34
34
|
"Server": "127.0.0.1",
|
|
35
|
-
"Port":
|
|
35
|
+
"Port": 27117,
|
|
36
36
|
"User": "",
|
|
37
37
|
"Password": "",
|
|
38
|
-
"Database": "
|
|
38
|
+
"Database": "meadow_conn_test",
|
|
39
39
|
"ConnectionPoolLimit": 20
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
const _AnimalSchema = {
|
|
44
|
+
TableName: 'Animal',
|
|
45
|
+
Columns: [
|
|
46
|
+
{ Column: 'IDAnimal', DataType: 'ID' },
|
|
47
|
+
{ Column: 'GUIDAnimal', DataType: 'GUID', Size: 36 },
|
|
48
|
+
{ Column: 'Name', DataType: 'String', Size: 128 },
|
|
49
|
+
{ Column: 'Age', DataType: 'Numeric' },
|
|
50
|
+
{ Column: 'Cost', DataType: 'Decimal', Size: '10,2' },
|
|
51
|
+
{ Column: 'Description', DataType: 'Text' },
|
|
52
|
+
{ Column: 'Birthday', DataType: 'DateTime' },
|
|
53
|
+
{ Column: 'Active', DataType: 'Boolean' },
|
|
54
|
+
{ Column: 'IDFarm', DataType: 'ForeignKey' }
|
|
55
|
+
]
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const _VehicleSchema = {
|
|
59
|
+
TableName: 'Vehicle',
|
|
60
|
+
Columns: [
|
|
61
|
+
{ Column: 'IDVehicle', DataType: 'ID' },
|
|
62
|
+
{ Column: 'GUIDVehicle', DataType: 'GUID', Size: 36 },
|
|
63
|
+
{ Column: 'Make', DataType: 'String', Size: 64 },
|
|
64
|
+
{ Column: 'Model', DataType: 'String', Size: 64 },
|
|
65
|
+
{ Column: 'Year', DataType: 'Numeric' }
|
|
66
|
+
]
|
|
67
|
+
};
|
|
68
|
+
|
|
43
69
|
suite
|
|
44
70
|
(
|
|
45
71
|
'Meadow-Connection-MongoDB',
|
|
@@ -96,22 +122,7 @@ suite
|
|
|
96
122
|
_Fable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
|
|
97
123
|
_Fable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
|
|
98
124
|
|
|
99
|
-
let
|
|
100
|
-
TableName: 'Animal',
|
|
101
|
-
Columns: [
|
|
102
|
-
{ Column: 'IDAnimal', DataType: 'ID' },
|
|
103
|
-
{ Column: 'GUIDAnimal', DataType: 'GUID', Size: 36 },
|
|
104
|
-
{ Column: 'Name', DataType: 'String', Size: 128 },
|
|
105
|
-
{ Column: 'Age', DataType: 'Numeric' },
|
|
106
|
-
{ Column: 'Cost', DataType: 'Decimal', Size: '10,2' },
|
|
107
|
-
{ Column: 'Description', DataType: 'Text' },
|
|
108
|
-
{ Column: 'Birthday', DataType: 'DateTime' },
|
|
109
|
-
{ Column: 'Active', DataType: 'Boolean' },
|
|
110
|
-
{ Column: 'IDFarm', DataType: 'ForeignKey' }
|
|
111
|
-
]
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
let tmpResult = _Fable.MeadowMongoDBProvider.generateCreateTableStatement(tmpSchema);
|
|
125
|
+
let tmpResult = _Fable.MeadowMongoDBProvider.generateCreateTableStatement(_AnimalSchema);
|
|
115
126
|
Expect(tmpResult.operation).to.equal('createCollection');
|
|
116
127
|
Expect(tmpResult.collection).to.equal('Animal');
|
|
117
128
|
Expect(tmpResult.indexes).to.be.an('array');
|
|
@@ -152,7 +163,7 @@ suite
|
|
|
152
163
|
_Fable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
|
|
153
164
|
|
|
154
165
|
let tmpURI = _Fable.MeadowMongoDBProvider._buildConnectionURI();
|
|
155
|
-
Expect(tmpURI).to.equal('mongodb://127.0.0.1:
|
|
166
|
+
Expect(tmpURI).to.equal('mongodb://127.0.0.1:27117/meadow_conn_test');
|
|
156
167
|
}
|
|
157
168
|
);
|
|
158
169
|
test
|
|
@@ -180,5 +191,440 @@ suite
|
|
|
180
191
|
);
|
|
181
192
|
}
|
|
182
193
|
);
|
|
194
|
+
suite
|
|
195
|
+
(
|
|
196
|
+
'Connection',
|
|
197
|
+
() =>
|
|
198
|
+
{
|
|
199
|
+
test
|
|
200
|
+
(
|
|
201
|
+
'connect with default fable.settings',
|
|
202
|
+
(fDone) =>
|
|
203
|
+
{
|
|
204
|
+
let _Fable = new libFable(_FableConfig);
|
|
205
|
+
_Fable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
|
|
206
|
+
_Fable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
|
|
207
|
+
|
|
208
|
+
Expect(_Fable.MeadowMongoDBProvider.connected).to.equal(false);
|
|
209
|
+
|
|
210
|
+
_Fable.MeadowMongoDBProvider.connect();
|
|
211
|
+
|
|
212
|
+
Expect(_Fable.MeadowMongoDBProvider.connected).to.equal(true);
|
|
213
|
+
Expect(_Fable.MeadowMongoDBProvider.pool).to.be.an('object');
|
|
214
|
+
|
|
215
|
+
// Verify we can actually communicate with MongoDB
|
|
216
|
+
_Fable.MeadowMongoDBProvider.pool.admin().ping()
|
|
217
|
+
.then((pResult) =>
|
|
218
|
+
{
|
|
219
|
+
Expect(pResult).to.have.property('ok');
|
|
220
|
+
Expect(pResult.ok).to.equal(1);
|
|
221
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
222
|
+
return fDone();
|
|
223
|
+
})
|
|
224
|
+
.catch((pError) =>
|
|
225
|
+
{
|
|
226
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
227
|
+
return fDone(pError);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
test
|
|
232
|
+
(
|
|
233
|
+
'connectAsync callback',
|
|
234
|
+
(fDone) =>
|
|
235
|
+
{
|
|
236
|
+
let _Fable = new libFable(_FableConfig);
|
|
237
|
+
_Fable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
|
|
238
|
+
_Fable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
|
|
239
|
+
|
|
240
|
+
_Fable.MeadowMongoDBProvider.connectAsync(
|
|
241
|
+
(pError, pDatabase) =>
|
|
242
|
+
{
|
|
243
|
+
Expect(pError).to.equal(null);
|
|
244
|
+
Expect(pDatabase).to.be.an('object');
|
|
245
|
+
Expect(_Fable.MeadowMongoDBProvider.connected).to.equal(true);
|
|
246
|
+
Expect(_Fable.MeadowMongoDBProvider.pool).to.equal(pDatabase);
|
|
247
|
+
|
|
248
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
249
|
+
return fDone();
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
);
|
|
253
|
+
test
|
|
254
|
+
(
|
|
255
|
+
'autoconnect via MeadowConnectionMongoDBAutoConnect',
|
|
256
|
+
(fDone) =>
|
|
257
|
+
{
|
|
258
|
+
let tmpConfig = JSON.parse(JSON.stringify(_FableConfig));
|
|
259
|
+
tmpConfig.MeadowConnectionMongoDBAutoConnect = true;
|
|
260
|
+
|
|
261
|
+
let _Fable = new libFable(tmpConfig);
|
|
262
|
+
_Fable.serviceManager.addAndInstantiateServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
|
|
263
|
+
|
|
264
|
+
Expect(_Fable.MeadowMongoDBProvider.connected).to.equal(true);
|
|
265
|
+
Expect(_Fable.MeadowMongoDBProvider.pool).to.be.an('object');
|
|
266
|
+
|
|
267
|
+
_Fable.MeadowMongoDBProvider.pool.admin().ping()
|
|
268
|
+
.then((pResult) =>
|
|
269
|
+
{
|
|
270
|
+
Expect(pResult.ok).to.equal(1);
|
|
271
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
272
|
+
return fDone();
|
|
273
|
+
})
|
|
274
|
+
.catch((pError) =>
|
|
275
|
+
{
|
|
276
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
277
|
+
return fDone(pError);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
test
|
|
282
|
+
(
|
|
283
|
+
'connect when already connected logs error and does not throw',
|
|
284
|
+
(fDone) =>
|
|
285
|
+
{
|
|
286
|
+
let _Fable = new libFable(_FableConfig);
|
|
287
|
+
_Fable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
|
|
288
|
+
_Fable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
|
|
289
|
+
|
|
290
|
+
_Fable.MeadowMongoDBProvider.connect();
|
|
291
|
+
Expect(_Fable.MeadowMongoDBProvider.connected).to.equal(true);
|
|
292
|
+
|
|
293
|
+
// Second connect should not throw
|
|
294
|
+
_Fable.MeadowMongoDBProvider.connect();
|
|
295
|
+
Expect(_Fable.MeadowMongoDBProvider.connected).to.equal(true);
|
|
296
|
+
|
|
297
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
298
|
+
return fDone();
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
test
|
|
302
|
+
(
|
|
303
|
+
'pass in your own settings and connect',
|
|
304
|
+
(fDone) =>
|
|
305
|
+
{
|
|
306
|
+
let _Fable = new libFable();
|
|
307
|
+
_Fable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
|
|
308
|
+
_Fable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider', {MongoDB: _FableConfig.MongoDB});
|
|
309
|
+
|
|
310
|
+
_Fable.MeadowMongoDBProvider.connect();
|
|
311
|
+
|
|
312
|
+
Expect(_Fable.MeadowMongoDBProvider.connected).to.equal(true);
|
|
313
|
+
|
|
314
|
+
_Fable.MeadowMongoDBProvider.pool.admin().ping()
|
|
315
|
+
.then((pResult) =>
|
|
316
|
+
{
|
|
317
|
+
Expect(pResult.ok).to.equal(1);
|
|
318
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
319
|
+
return fDone();
|
|
320
|
+
})
|
|
321
|
+
.catch((pError) =>
|
|
322
|
+
{
|
|
323
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
324
|
+
return fDone(pError);
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
suite
|
|
331
|
+
(
|
|
332
|
+
'Collection & Index Creation',
|
|
333
|
+
() =>
|
|
334
|
+
{
|
|
335
|
+
let _Fable = null;
|
|
336
|
+
|
|
337
|
+
suiteSetup
|
|
338
|
+
(
|
|
339
|
+
(fDone) =>
|
|
340
|
+
{
|
|
341
|
+
_Fable = new libFable(_FableConfig);
|
|
342
|
+
_Fable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
|
|
343
|
+
_Fable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
|
|
344
|
+
_Fable.MeadowMongoDBProvider.connect();
|
|
345
|
+
|
|
346
|
+
// Drop any leftover test collections
|
|
347
|
+
let tmpDb = _Fable.MeadowMongoDBProvider.pool;
|
|
348
|
+
Promise.all([
|
|
349
|
+
tmpDb.collection('Animal').drop().catch(() => {}),
|
|
350
|
+
tmpDb.collection('Vehicle').drop().catch(() => {})
|
|
351
|
+
])
|
|
352
|
+
.then(() => fDone())
|
|
353
|
+
.catch(() => fDone());
|
|
354
|
+
}
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
suiteTeardown
|
|
358
|
+
(
|
|
359
|
+
(fDone) =>
|
|
360
|
+
{
|
|
361
|
+
let tmpDb = _Fable.MeadowMongoDBProvider.pool;
|
|
362
|
+
Promise.all([
|
|
363
|
+
tmpDb.collection('Animal').drop().catch(() => {}),
|
|
364
|
+
tmpDb.collection('Vehicle').drop().catch(() => {})
|
|
365
|
+
])
|
|
366
|
+
.then(() =>
|
|
367
|
+
{
|
|
368
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
369
|
+
fDone();
|
|
370
|
+
})
|
|
371
|
+
.catch(() =>
|
|
372
|
+
{
|
|
373
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
374
|
+
fDone();
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
test
|
|
380
|
+
(
|
|
381
|
+
'createTable creates collection and indexes',
|
|
382
|
+
(fDone) =>
|
|
383
|
+
{
|
|
384
|
+
_Fable.MeadowMongoDBProvider.createTable(_AnimalSchema,
|
|
385
|
+
(pError) =>
|
|
386
|
+
{
|
|
387
|
+
Expect(pError).to.not.be.an('error');
|
|
388
|
+
|
|
389
|
+
let tmpDb = _Fable.MeadowMongoDBProvider.pool;
|
|
390
|
+
|
|
391
|
+
// Verify collection exists
|
|
392
|
+
tmpDb.listCollections({ name: 'Animal' }).toArray()
|
|
393
|
+
.then((pCollections) =>
|
|
394
|
+
{
|
|
395
|
+
Expect(pCollections.length).to.equal(1);
|
|
396
|
+
Expect(pCollections[0].name).to.equal('Animal');
|
|
397
|
+
|
|
398
|
+
// Verify indexes were created
|
|
399
|
+
return tmpDb.collection('Animal').indexes();
|
|
400
|
+
})
|
|
401
|
+
.then((pIndexes) =>
|
|
402
|
+
{
|
|
403
|
+
// _id (default) + IDAnimal + GUIDAnimal + IDFarm = 4
|
|
404
|
+
Expect(pIndexes.length).to.equal(4);
|
|
405
|
+
|
|
406
|
+
// Find our custom indexes
|
|
407
|
+
let tmpIdAnimalIdx = pIndexes.find((pIdx) => pIdx.name === 'idx_IDAnimal_unique');
|
|
408
|
+
Expect(tmpIdAnimalIdx).to.be.an('object');
|
|
409
|
+
Expect(tmpIdAnimalIdx.unique).to.equal(true);
|
|
410
|
+
|
|
411
|
+
let tmpGuidIdx = pIndexes.find((pIdx) => pIdx.name === 'idx_GUIDAnimal_unique');
|
|
412
|
+
Expect(tmpGuidIdx).to.be.an('object');
|
|
413
|
+
Expect(tmpGuidIdx.unique).to.equal(true);
|
|
414
|
+
|
|
415
|
+
let tmpForeignKeyIdx = pIndexes.find((pIdx) => pIdx.name === 'idx_IDFarm');
|
|
416
|
+
Expect(tmpForeignKeyIdx).to.be.an('object');
|
|
417
|
+
|
|
418
|
+
return fDone();
|
|
419
|
+
})
|
|
420
|
+
.catch((pError) => fDone(pError));
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
);
|
|
424
|
+
test
|
|
425
|
+
(
|
|
426
|
+
'createTable is idempotent',
|
|
427
|
+
(fDone) =>
|
|
428
|
+
{
|
|
429
|
+
// Call createTable again for the same schema — should not error
|
|
430
|
+
_Fable.MeadowMongoDBProvider.createTable(_AnimalSchema,
|
|
431
|
+
(pError) =>
|
|
432
|
+
{
|
|
433
|
+
Expect(pError).to.not.be.an('error');
|
|
434
|
+
return fDone();
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
);
|
|
438
|
+
test
|
|
439
|
+
(
|
|
440
|
+
'createTables creates multiple collections',
|
|
441
|
+
(fDone) =>
|
|
442
|
+
{
|
|
443
|
+
let tmpMultiSchema = {
|
|
444
|
+
Tables: [_AnimalSchema, _VehicleSchema]
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
_Fable.MeadowMongoDBProvider.createTables(tmpMultiSchema,
|
|
448
|
+
(pError) =>
|
|
449
|
+
{
|
|
450
|
+
Expect(pError).to.not.be.an('error');
|
|
451
|
+
|
|
452
|
+
let tmpDb = _Fable.MeadowMongoDBProvider.pool;
|
|
453
|
+
tmpDb.listCollections().toArray()
|
|
454
|
+
.then((pCollections) =>
|
|
455
|
+
{
|
|
456
|
+
let tmpNames = pCollections.map((pC) => pC.name);
|
|
457
|
+
Expect(tmpNames).to.include('Animal');
|
|
458
|
+
Expect(tmpNames).to.include('Vehicle');
|
|
459
|
+
return fDone();
|
|
460
|
+
})
|
|
461
|
+
.catch((pError) => fDone(pError));
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
);
|
|
465
|
+
test
|
|
466
|
+
(
|
|
467
|
+
'createTable when not connected returns error',
|
|
468
|
+
(fDone) =>
|
|
469
|
+
{
|
|
470
|
+
// Create a disconnected provider (no connect() call)
|
|
471
|
+
let tmpFable = new libFable(_FableConfig);
|
|
472
|
+
tmpFable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
|
|
473
|
+
tmpFable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
|
|
474
|
+
|
|
475
|
+
tmpFable.MeadowMongoDBProvider.createTable(_AnimalSchema,
|
|
476
|
+
(pError) =>
|
|
477
|
+
{
|
|
478
|
+
Expect(pError).to.be.an('error');
|
|
479
|
+
Expect(pError.message).to.contain('Not connected');
|
|
480
|
+
return fDone();
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
);
|
|
486
|
+
suite
|
|
487
|
+
(
|
|
488
|
+
'Raw MongoDB Operations',
|
|
489
|
+
() =>
|
|
490
|
+
{
|
|
491
|
+
let _Fable = null;
|
|
492
|
+
|
|
493
|
+
suiteSetup
|
|
494
|
+
(
|
|
495
|
+
(fDone) =>
|
|
496
|
+
{
|
|
497
|
+
_Fable = new libFable(_FableConfig);
|
|
498
|
+
_Fable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
|
|
499
|
+
_Fable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
|
|
500
|
+
_Fable.MeadowMongoDBProvider.connect();
|
|
501
|
+
|
|
502
|
+
// Set up a clean test collection with indexes
|
|
503
|
+
let tmpDb = _Fable.MeadowMongoDBProvider.pool;
|
|
504
|
+
tmpDb.collection('RawTestAnimal').drop()
|
|
505
|
+
.catch(() => {})
|
|
506
|
+
.then(() =>
|
|
507
|
+
{
|
|
508
|
+
return tmpDb.createCollection('RawTestAnimal');
|
|
509
|
+
})
|
|
510
|
+
.then(() =>
|
|
511
|
+
{
|
|
512
|
+
return fDone();
|
|
513
|
+
})
|
|
514
|
+
.catch((pError) => fDone(pError));
|
|
515
|
+
}
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
suiteTeardown
|
|
519
|
+
(
|
|
520
|
+
(fDone) =>
|
|
521
|
+
{
|
|
522
|
+
let tmpDb = _Fable.MeadowMongoDBProvider.pool;
|
|
523
|
+
tmpDb.collection('RawTestAnimal').drop()
|
|
524
|
+
.catch(() => {})
|
|
525
|
+
.then(() =>
|
|
526
|
+
{
|
|
527
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
528
|
+
return fDone();
|
|
529
|
+
})
|
|
530
|
+
.catch(() =>
|
|
531
|
+
{
|
|
532
|
+
_Fable.MeadowMongoDBProvider.client.close();
|
|
533
|
+
return fDone();
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
test
|
|
539
|
+
(
|
|
540
|
+
'insert and find documents',
|
|
541
|
+
(fDone) =>
|
|
542
|
+
{
|
|
543
|
+
let tmpCollection = _Fable.MeadowMongoDBProvider.pool.collection('RawTestAnimal');
|
|
544
|
+
|
|
545
|
+
tmpCollection.insertMany([
|
|
546
|
+
{ IDAnimal: 1, Name: 'Fido', Type: 'Dog' },
|
|
547
|
+
{ IDAnimal: 2, Name: 'Whiskers', Type: 'Cat' },
|
|
548
|
+
{ IDAnimal: 3, Name: 'Polly', Type: 'Parrot' }
|
|
549
|
+
])
|
|
550
|
+
.then(() =>
|
|
551
|
+
{
|
|
552
|
+
return tmpCollection.find({}).sort({ IDAnimal: 1 }).toArray();
|
|
553
|
+
})
|
|
554
|
+
.then((pDocs) =>
|
|
555
|
+
{
|
|
556
|
+
Expect(pDocs).to.be.an('array');
|
|
557
|
+
Expect(pDocs.length).to.equal(3);
|
|
558
|
+
Expect(pDocs[0].Name).to.equal('Fido');
|
|
559
|
+
Expect(pDocs[1].Name).to.equal('Whiskers');
|
|
560
|
+
Expect(pDocs[2].Name).to.equal('Polly');
|
|
561
|
+
return fDone();
|
|
562
|
+
})
|
|
563
|
+
.catch((pError) => fDone(pError));
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
test
|
|
567
|
+
(
|
|
568
|
+
'update a document',
|
|
569
|
+
(fDone) =>
|
|
570
|
+
{
|
|
571
|
+
let tmpCollection = _Fable.MeadowMongoDBProvider.pool.collection('RawTestAnimal');
|
|
572
|
+
|
|
573
|
+
tmpCollection.updateOne(
|
|
574
|
+
{ IDAnimal: 1 },
|
|
575
|
+
{ $set: { Name: 'Rex' } }
|
|
576
|
+
)
|
|
577
|
+
.then((pResult) =>
|
|
578
|
+
{
|
|
579
|
+
Expect(pResult.modifiedCount).to.equal(1);
|
|
580
|
+
return tmpCollection.findOne({ IDAnimal: 1 });
|
|
581
|
+
})
|
|
582
|
+
.then((pDoc) =>
|
|
583
|
+
{
|
|
584
|
+
Expect(pDoc.Name).to.equal('Rex');
|
|
585
|
+
return fDone();
|
|
586
|
+
})
|
|
587
|
+
.catch((pError) => fDone(pError));
|
|
588
|
+
}
|
|
589
|
+
);
|
|
590
|
+
test
|
|
591
|
+
(
|
|
592
|
+
'delete a document',
|
|
593
|
+
(fDone) =>
|
|
594
|
+
{
|
|
595
|
+
let tmpCollection = _Fable.MeadowMongoDBProvider.pool.collection('RawTestAnimal');
|
|
596
|
+
|
|
597
|
+
tmpCollection.deleteOne({ IDAnimal: 3 })
|
|
598
|
+
.then((pResult) =>
|
|
599
|
+
{
|
|
600
|
+
Expect(pResult.deletedCount).to.equal(1);
|
|
601
|
+
return tmpCollection.countDocuments();
|
|
602
|
+
})
|
|
603
|
+
.then((pCount) =>
|
|
604
|
+
{
|
|
605
|
+
Expect(pCount).to.equal(2);
|
|
606
|
+
return fDone();
|
|
607
|
+
})
|
|
608
|
+
.catch((pError) => fDone(pError));
|
|
609
|
+
}
|
|
610
|
+
);
|
|
611
|
+
test
|
|
612
|
+
(
|
|
613
|
+
'count documents with filter',
|
|
614
|
+
(fDone) =>
|
|
615
|
+
{
|
|
616
|
+
let tmpCollection = _Fable.MeadowMongoDBProvider.pool.collection('RawTestAnimal');
|
|
617
|
+
|
|
618
|
+
tmpCollection.countDocuments({ Type: 'Dog' })
|
|
619
|
+
.then((pCount) =>
|
|
620
|
+
{
|
|
621
|
+
Expect(pCount).to.equal(1);
|
|
622
|
+
return fDone();
|
|
623
|
+
})
|
|
624
|
+
.catch((pError) => fDone(pError));
|
|
625
|
+
}
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
);
|
|
183
629
|
}
|
|
184
630
|
);
|