@mongoosejs/studio 0.1.20 → 0.2.0
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/backend/actions/ChatMessage/executeScript.js +4 -1
- package/backend/actions/ChatThread/createChatMessage.js +28 -22
- package/backend/helpers/evaluateFilter.js +38 -1
- package/express.js +4 -2
- package/frontend/public/app.js +702 -428
- package/frontend/public/index.html +1 -1
- package/frontend/public/style.css +1 -1
- package/frontend/public/tw.css +81 -62
- package/frontend/src/_util/document-search-autocomplete.js +229 -0
- package/frontend/src/chat/chat-message-script/chat-message-script.html +27 -20
- package/frontend/src/chat/chat.html +20 -17
- package/frontend/src/chat/chat.js +2 -0
- package/frontend/src/document/document.css +1 -8
- package/frontend/src/document/document.html +202 -164
- package/frontend/src/document/document.js +1 -0
- package/frontend/src/document-details/document-details.html +1 -11
- package/frontend/src/document-details/document-details.js +43 -1
- package/frontend/src/document-details/document-property/document-property.html +4 -4
- package/frontend/src/index.js +36 -15
- package/frontend/src/json-node/json-node.html +118 -0
- package/frontend/src/json-node/json-node.js +272 -0
- package/frontend/src/list-array/list-array.html +15 -3
- package/frontend/src/list-array/list-array.js +21 -3
- package/frontend/src/list-default/list-default.js +2 -2
- package/frontend/src/list-json/list-json.html +1 -1
- package/frontend/src/list-json/list-json.js +11 -273
- package/frontend/src/list-subdocument/list-subdocument.html +13 -4
- package/frontend/src/list-subdocument/list-subdocument.js +11 -6
- package/frontend/src/models/document-search/document-search.html +1 -1
- package/frontend/src/models/document-search/document-search.js +22 -116
- package/frontend/src/models/models.css +5 -15
- package/frontend/src/models/models.html +34 -34
- package/frontend/src/navbar/navbar.html +15 -6
- package/package.json +2 -2
|
@@ -39,7 +39,10 @@ module.exports = ({ db, studioConnection }) => async function executeScript(para
|
|
|
39
39
|
|
|
40
40
|
// Create a sandbox with the db object
|
|
41
41
|
const logs = [];
|
|
42
|
-
|
|
42
|
+
if (!db.Types) {
|
|
43
|
+
db.Types = mongoose.Types;
|
|
44
|
+
}
|
|
45
|
+
const sandbox = { db, mongoose, console: {}, ObjectId: mongoose.Types.ObjectId };
|
|
43
46
|
|
|
44
47
|
// Capture console logs
|
|
45
48
|
sandbox.console.log = function() {
|
|
@@ -101,42 +101,48 @@ module.exports = ({ db, studioConnection, options }) => async function createCha
|
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
const systemPrompt = `
|
|
104
|
-
|
|
104
|
+
You are a data querying assistant who writes scripts for users accessing MongoDB data using Node.js and Mongoose.
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
The following globals are available. Assume no other globals exist.
|
|
107
|
+
- db: The Mongoose connection object or Mongoose singleton depending on what the user passed in
|
|
108
|
+
- mongoose: the output of require('mongoose').
|
|
109
|
+
- ObjectId: MongoDB ObjectId class from mongoose.Types.ObjectId
|
|
110
|
+
- console: has a stubbed log() function that logs to the console and is accessible in the output.
|
|
107
111
|
|
|
108
|
-
|
|
112
|
+
Keep scripts concise. Avoid unnecessary comments, error handling, and temporary variables.
|
|
109
113
|
|
|
110
|
-
|
|
114
|
+
Do not write any imports or require() statements, that will cause the script to break.
|
|
111
115
|
|
|
112
|
-
|
|
116
|
+
If the user approves the script, the script will run in the Node.js server in a sandboxed vm.createContext() call with only 1 global variable: db, which contains the Mongoose connection. The script return value will then send the response via JSON to the client. Be aware that the result of the query will be serialized to JSON before being displayed to the user. MAKE SURE TO RETURN A VALUE FROM THE SCRIPT.
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
Optimize scripts for readability first, followed by reliability, followed by performance. Avoid using the aggregation framework unless explicitly requested by the user. Use indexed fields in queries where possible.
|
|
115
119
|
|
|
116
|
-
|
|
120
|
+
Assume the user has pre-defined schemas and models. Do not define any new schemas or models for the user.
|
|
117
121
|
|
|
118
|
-
|
|
122
|
+
Use async/await where possible. Assume top-level await is allowed.
|
|
119
123
|
|
|
120
|
-
|
|
124
|
+
Write at most one script, unless the user explicitly asks for multiple scripts.
|
|
121
125
|
|
|
122
|
-
|
|
126
|
+
Think carefully about the user's input and identify the models referred to by the user's query.
|
|
123
127
|
|
|
124
|
-
|
|
128
|
+
Format output as Markdown, including code fences for any scripts the user requested.
|
|
125
129
|
|
|
126
|
-
|
|
130
|
+
Add a brief text description of what the script does.
|
|
127
131
|
|
|
128
|
-
|
|
132
|
+
If the user's query is best answered with a chart, return a Chart.js 4 configuration as \`return { $chart: chartJSConfig };\`. Disable ChartJS animation by default unless user asks for it. Set responsive: true, maintainAspectRatio: false options unless the user explicitly asks.
|
|
129
133
|
|
|
130
|
-
|
|
134
|
+
If the user\'s query is best answered by a map, return an object { $featureCollection } which contains a GeoJSON FeatureCollection
|
|
131
135
|
|
|
132
|
-
|
|
136
|
+
Example output:
|
|
133
137
|
|
|
134
|
-
|
|
135
|
-
const users = await db.model('User').find({ isDeleted: false });
|
|
136
|
-
return { numUsers: users.length };
|
|
137
|
-
\`\`\`
|
|
138
|
+
The following script counts the number of users which are not deleted.
|
|
138
139
|
|
|
139
|
-
|
|
140
|
+
\`\`\`javascript
|
|
141
|
+
const users = await db.model('User').find({ isDeleted: false });
|
|
142
|
+
return { numUsers: users.length };
|
|
143
|
+
\`\`\`
|
|
140
144
|
|
|
141
|
-
|
|
142
|
-
|
|
145
|
+
-----------
|
|
146
|
+
|
|
147
|
+
Here is a description of the user's models. Assume these are the only models available in the system unless explicitly instructed otherwise by the user.
|
|
148
|
+
`.trim();
|
|
@@ -29,7 +29,8 @@ module.exports = function evaluateFilter(searchText) {
|
|
|
29
29
|
const context = vm.createContext({
|
|
30
30
|
ObjectId,
|
|
31
31
|
Date,
|
|
32
|
-
Math
|
|
32
|
+
Math,
|
|
33
|
+
objectIdRange
|
|
33
34
|
});
|
|
34
35
|
|
|
35
36
|
let result;
|
|
@@ -49,3 +50,39 @@ module.exports = function evaluateFilter(searchText) {
|
|
|
49
50
|
|
|
50
51
|
throw new Error('Invalid search filter: must evaluate to an object');
|
|
51
52
|
};
|
|
53
|
+
|
|
54
|
+
function objectIdRange(start, end) {
|
|
55
|
+
if (start instanceof Date) {
|
|
56
|
+
start = ObjectId.createFromTime(start.getTime() / 1000);
|
|
57
|
+
} else if (typeof start === 'string') {
|
|
58
|
+
if (/^[a-fA-F0-9]{24}$/.test(start)) {
|
|
59
|
+
start = new ObjectId(start);
|
|
60
|
+
} else if (!Number.isNaN(new Date(start).valueOf())) {
|
|
61
|
+
start = ObjectId.createFromTime(new Date(start).getTime() / 1000);
|
|
62
|
+
} else {
|
|
63
|
+
throw new Error('Invalid start');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (end instanceof Date) {
|
|
67
|
+
end = ObjectId.createFromTime(end.getTime() / 1000);
|
|
68
|
+
} else if (typeof end === 'string') {
|
|
69
|
+
if (/^[a-fA-F0-9]{24}$/.test(end)) {
|
|
70
|
+
end = new ObjectId(end);
|
|
71
|
+
} else if (!Number.isNaN(new Date(end).valueOf())) {
|
|
72
|
+
end = ObjectId.createFromTime(new Date(end).getTime() / 1000);
|
|
73
|
+
} else {
|
|
74
|
+
throw new Error('Invalid end');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (start != null && end != null) {
|
|
79
|
+
return { $gte: start, $lte: end };
|
|
80
|
+
}
|
|
81
|
+
if (start != null) {
|
|
82
|
+
return { $gte: start };
|
|
83
|
+
}
|
|
84
|
+
if (end != null) {
|
|
85
|
+
return { $lte: end };
|
|
86
|
+
}
|
|
87
|
+
throw new Error('objectIdRange requires at least one parameter (start or end)');
|
|
88
|
+
}
|
package/express.js
CHANGED
|
@@ -61,7 +61,7 @@ module.exports = async function mongooseStudioExpressApp(apiUrl, conn, options)
|
|
|
61
61
|
.then(res => res.json())
|
|
62
62
|
.then(({ user, roles }) => {
|
|
63
63
|
if (!user || !roles) {
|
|
64
|
-
|
|
64
|
+
return res.status(403).json({ message: 'Not authorized' });
|
|
65
65
|
}
|
|
66
66
|
req._internals = req._internals || {};
|
|
67
67
|
req._internals.authorization = authorization;
|
|
@@ -71,7 +71,9 @@ module.exports = async function mongooseStudioExpressApp(apiUrl, conn, options)
|
|
|
71
71
|
|
|
72
72
|
next();
|
|
73
73
|
})
|
|
74
|
-
.catch(err =>
|
|
74
|
+
.catch(err => {
|
|
75
|
+
return res.status(500).json({ message: err.message });
|
|
76
|
+
});
|
|
75
77
|
},
|
|
76
78
|
express.json(),
|
|
77
79
|
objectRouter(backend, toRoute)
|