2
0
mirror of https://github.com/frappe/books.git synced 2025-02-02 12:08:27 +00:00

more camelCase

This commit is contained in:
Rushabh Mehta 2018-02-08 17:58:51 +05:30
parent dfdb18b5bc
commit bc095b5bc3
24 changed files with 99 additions and 87 deletions

View File

@ -34,7 +34,7 @@ module.exports = class FormPage extends Page {
async show_doc(doctype, name) { async show_doc(doctype, name) {
try { try {
this.doc = await frappe.get_doc(doctype, name); this.doc = await frappe.getDoc(doctype, name);
this.form.use(this.doc); this.form.use(this.doc);
} catch (e) { } catch (e) {
this.renderError(e.status_code, e.message); this.renderError(e.status_code, e.message);

View File

@ -49,7 +49,7 @@ module.exports = class Desk {
}) })
frappe.router.add('new/:doctype', async (params) => { frappe.router.add('new/:doctype', async (params) => {
let doc = await frappe.get_new_doc(params.doctype); let doc = await frappe.getNewDoc(params.doctype);
// unset the name, its local // unset the name, its local
await frappe.router.setRoute('edit', doc.doctype, doc.name); await frappe.router.setRoute('edit', doc.doctype, doc.name);
await doc.set('name', ''); await doc.set('name', '');

View File

@ -4,12 +4,12 @@ Frappe.js comes in with built-in controls for various types of inputs
## Creating ## Creating
A new control can be created with `control.make_control` method. A new control can be created with `control.makeControl` method.
```js ```js
const controls = require('./controls'); const controls = require('./controls');
let control = controls.make_control({ let control = controls.makeControl({
fieldname: 'test', fieldname: 'test',
fieldtype: 'Data', fieldtype: 'Data',
label: 'Test Control' label: 'Test Control'
@ -20,7 +20,7 @@ let control = controls.make_control({
The control has the following structure of HTML Elements The control has the following structure of HTML Elements
- `form_group` - `formGroup`
- `label` - `label`
- `input` - `input`
- `description` - `description`
@ -46,7 +46,7 @@ Options can be set in the `options` property as a list
Example: Example:
```js ```js
let control = controls.make_control({ let control = controls.makeControl({
fieldname: 'test', fieldname: 'test',
fieldtype: 'Select', fieldtype: 'Select',
label: 'Test Select', label: 'Test Select',
@ -64,10 +64,25 @@ You can select a value from another DocType with a Link type field. The value of
Example: Example:
```js ```js
let control = controls.make_control({ let control = controls.makeControl({
fieldname: 'user', fieldname: 'user',
fieldtype: 'Link', fieldtype: 'Link',
label: 'User', label: 'User',
target: 'User' target: 'User'
}, body); }, body);
``` ```
## Table
A table control renders a grid object (datatable). The columns of the table are defined by the `childtype` property of the field definition
Example:
```js
let control = controls.makeControl({
fieldname: 'roles',
fieldtype: 'Table',
label: 'Roles',
childtype: 'User Role'
}, body);
```

View File

@ -78,10 +78,10 @@ To setup a form for a new document, just create a new document with the Frappe.j
frappe.router.add('new/todo', async (params) => { frappe.router.add('new/todo', async (params) => {
// new document // new document
app.doc = await frappe.get_doc({doctype: 'ToDo'}); app.doc = await frappe.getDoc({doctype: 'ToDo'});
// set a random name // set a random name
app.doc.set_name(); app.doc.setName();
// show the page // show the page
app.edit_page.show(); app.edit_page.show();

View File

@ -48,13 +48,13 @@ You can manage documents, using the same Document API as if it were a local data
```js ```js
await frappe.init(); await frappe.init();
await frappe.init_db('rest', {server: 'localhost:8000'}); await frappe.initDb('rest', {server: 'localhost:8000'});
let doc = await frappe.get_doc({doctype:'ToDo', subject:'test rest insert 1'}); let doc = await frappe.getDoc({doctype:'ToDo', subject:'test rest insert 1'});
await doc.insert(); await doc.insert();
doc.subject = 'subject changed'; doc.subject = 'subject changed';
await doc.update(); await doc.update();
let data = await frappe.db.get_all({doctype:'ToDo'}); let data = await frappe.db.getAll({doctype:'ToDo'});
``` ```

View File

@ -39,10 +39,10 @@ Lists can be extended by defining a client module for the doctype, similar to fo
const BaseList = require('frappejs/client/view/list'); const BaseList = require('frappejs/client/view/list');
class ToDoList extends BaseList { class ToDoList extends BaseList {
get_fields() { getFields() {
return ['name', 'subject', 'status']; return ['name', 'subject', 'status'];
} }
get_row_html(data) { getRowHTML(data) {
let symbol = data.status=="Closed" ? "✔" : ""; let symbol = data.status=="Closed" ? "✔" : "";
return `<a href="#edit/todo/${data.name}">${symbol} ${data.subject}</a>`; return `<a href="#edit/todo/${data.name}">${symbol} ${data.subject}</a>`;
} }

View File

@ -17,14 +17,11 @@ let todo_list = new Page('ToDo List');
// make the current page active // make the current page active
todo_list.show(); todo_list.show();
```
```js
// to do list // to do list
frappe.router.add('default', () => { frappe.router.add('default', () => {
app.todo_list.show(); todo_list.show();
app.todo_list.list.run(); todo_list.list.run();
}); });
// setup todo form // setup todo form
@ -48,18 +45,18 @@ frappe.router.add('new/todo', async (params) => {
You can change route with You can change route with
```js ```js
await frappe.router.set_route('list', 'todo'); await frappe.router.setRoute('list', 'todo');
``` ```
## Getting current route ## Getting current route
`frappe.router.get_route()` will return the current route as a list. `frappe.router.getRoute()` will return the current route as a list.
```js ```js
await frappe.router.set_route('list', 'todo'); await frappe.router.setRoute('list', 'todo');
// returns ['list', 'todo']; // returns ['list', 'todo'];
route = frappe.router.get_route(); route = frappe.router.getRoute();
``` ```
## Show a route ## Show a route

View File

@ -40,13 +40,13 @@ The `meta` class contains actions that are done on a group of objects and a docu
```js ```js
// extend the meta class // extend the meta class
class todo_meta extends frappe.meta.Meta { class todo_meta extends frappe.meta.Meta {
setup_meta() { setupMeta() {
Object.assign(this, require('./todo.json')); Object.assign(this, require('./todo.json'));
this.name = 'ToDo'; this.name = 'ToDo';
this.list_options.fields = ['name', 'subject', 'status', 'description']; this.list_options.fields = ['name', 'subject', 'status', 'description'];
} }
get_row_html(data) { getRowHTML(data) {
return `<a href="#edit/todo/${data.name}">${data.subject}</a>`; return `<a href="#edit/todo/${data.name}">${data.subject}</a>`;
} }

View File

@ -8,11 +8,11 @@ All document write methods are asynchronous and return javascript Promise object
### Initialize ### Initialize
Documents are initialized with the `frappe.get_doc` method. If `doctype` and `name` are passed as parameters, then the document is fetched from the backend. If a simple object is passed, then object properties are set in the document. Documents are initialized with the `frappe.getDoc` method. If `doctype` and `name` are passed as parameters, then the document is fetched from the backend. If a simple object is passed, then object properties are set in the document.
```js ```js
// make a new todo // make a new todo
let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'}); let todo = await frappe.getDoc({doctype: 'ToDo', subject: 'something'});
``` ```
### Create ### Create
@ -21,18 +21,18 @@ You can insert a document in the backend with the `insert` method.
```js ```js
// make a new todo // make a new todo
let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'}); let todo = await frappe.getDoc({doctype: 'ToDo', subject: 'something'});
await todo.insert(); await todo.insert();
``` ```
### Read ### Read
You can read a document from the backend with the `frappe.get_doc` method You can read a document from the backend with the `frappe.getDoc` method
```js ```js
// get all open todos // get all open todos
let todos = await frappe.db.get_all({doctype:'ToDo', fields:['name'], filters: {status: "Open"}); let todos = await frappe.db.getAll({doctype:'ToDo', fields:['name'], filters: {status: "Open"});
let first_todo = await frappe.get_doc('ToDo', toods[0].name); let first_todo = await frappe.getDoc('ToDo', toods[0].name);
``` ```
### Update ### Update
@ -41,8 +41,8 @@ The `update` method updates a document.
```js ```js
// get all open todos // get all open todos
let todos = await frappe.db.get_all({doctype:'ToDo', fields:['name'], filters: {status: "Open"}); let todos = await frappe.db.getAll({doctype:'ToDo', fields:['name'], filters: {status: "Open"});
let first_todo = await frappe.get_doc('ToDo', toods[0].name); let first_todo = await frappe.getDoc('ToDo', toods[0].name);
first_todo.status = 'Closed'; first_todo.status = 'Closed';
await first_todo.update(); await first_todo.update();
@ -54,8 +54,8 @@ The `delete` method deletes a document.
```js ```js
// get all open todos // get all open todos
let todos = await frappe.db.get_all({doctype:'ToDo', fields:['name'], filters: {status: "Open"}); let todos = await frappe.db.getAll({doctype:'ToDo', fields:['name'], filters: {status: "Open"});
let first_todo = await frappe.get_doc('ToDo', toods[0].name); let first_todo = await frappe.getDoc('ToDo', toods[0].name);
await first_todo.delete(); await first_todo.delete();
``` ```

View File

@ -1,11 +1,11 @@
# Metadata # Metadata
Metadata are first class objects in Frappe.js. You can get a metadata object by `frappe.get_meta`. All objects from the `models` folders of all modules are loaded. Metadata are first class objects in Frappe.js. You can get a metadata object by `frappe.getMeta`. All objects from the `models` folders of all modules are loaded.
### Example ### Example
```js ```js
let todo_meta = frappe.get_meta('ToDo'); let todo_meta = frappe.getMeta('ToDo');
// get all fields of type "Data" // get all fields of type "Data"
let data_fields = todo_meta.fields.map(d => d.fieldtype=='Data' ? d : null); let data_fields = todo_meta.fields.map(d => d.fieldtype=='Data' ? d : null);

View File

@ -1,19 +1,19 @@
module.exports = { module.exports = {
async init() { async init() {
if (this._initialized) return; if (this._initialized) return;
this.init_config(); this.initConfig();
this.init_globals(); this.initGlobals();
this._initialized = true; this._initialized = true;
}, },
init_config() { initConfig() {
this.config = { this.config = {
backend: 'sqlite', backend: 'sqlite',
port: 8000 port: 8000
}; };
}, },
init_globals() { initGlobals() {
this.meta_cache = {}; this.meta_cache = {};
this.modules = {}; this.modules = {};
this.docs = {}; this.docs = {};
@ -22,7 +22,7 @@ module.exports = {
} }
}, },
add_to_cache(doc) { addToCache(doc) {
if (!this.flags.cache_docs) return; if (!this.flags.cache_docs) return;
// add to `docs` cache // add to `docs` cache
@ -34,7 +34,7 @@ module.exports = {
} }
}, },
get_doc_from_cache(doctype, name) { getDocFromCache(doctype, name) {
if (this.docs[doctype] && this.docs[doctype][name]) { if (this.docs[doctype] && this.docs[doctype][name]) {
return this.docs[doctype][name]; return this.docs[doctype][name];
} }
@ -42,12 +42,12 @@ module.exports = {
getMeta(doctype) { getMeta(doctype) {
if (!this.meta_cache[doctype]) { if (!this.meta_cache[doctype]) {
this.meta_cache[doctype] = new (this.getMeta_class(doctype))(); this.meta_cache[doctype] = new (this.getMetaClass(doctype))();
} }
return this.meta_cache[doctype]; return this.meta_cache[doctype];
}, },
getMeta_class(doctype) { getMetaClass(doctype) {
doctype = this.slug(doctype); doctype = this.slug(doctype);
if (this.modules[doctype] && this.modules[doctype].Meta) { if (this.modules[doctype] && this.modules[doctype].Meta) {
return this.modules[doctype].Meta; return this.modules[doctype].Meta;
@ -56,23 +56,23 @@ module.exports = {
} }
}, },
async get_doc(doctype, name) { async getDoc(doctype, name) {
let doc = this.get_doc_from_cache(doctype, name); let doc = this.getDocFromCache(doctype, name);
if (!doc) { if (!doc) {
let controller_class = this.get_controller_class(doctype); let controller_class = this.getControllerClass(doctype);
doc = new controller_class({doctype:doctype, name: name}); doc = new controller_class({doctype:doctype, name: name});
await doc.load(); await doc.load();
this.add_to_cache(doc); this.addToCache(doc);
} }
return doc; return doc;
}, },
new_doc(data) { newDoc(data) {
let controller_class = this.get_controller_class(data.doctype); let controller_class = this.getControllerClass(data.doctype);
return new controller_class(data); return new controller_class(data);
}, },
get_controller_class(doctype) { getControllerClass(doctype) {
doctype = this.slug(doctype); doctype = this.slug(doctype);
if (this.modules[doctype] && this.modules[doctype].Document) { if (this.modules[doctype] && this.modules[doctype].Document) {
return this.modules[doctype].Document; return this.modules[doctype].Document;
@ -81,16 +81,16 @@ module.exports = {
} }
}, },
async get_new_doc(doctype) { async getNewDoc(doctype) {
let doc = frappe.new_doc({doctype: doctype}); let doc = this.newDoc({doctype: doctype});
doc.setName(); doc.setName();
doc.__not_inserted = true; doc.__not_inserted = true;
this.add_to_cache(doc); this.addToCache(doc);
return doc; return doc;
}, },
async insert(data) { async insert(data) {
return await (this.new_doc(data)).insert(); return await (this.newDoc(data)).insert();
}, },
login(user='guest', user_key) { login(user='guest', user_key) {

View File

@ -28,7 +28,7 @@ module.exports = {
const BaseDocument = require('frappejs/model/document'); const BaseDocument = require('frappejs/model/document');
class ${thinname}Meta extends BaseMeta { class ${thinname}Meta extends BaseMeta {
setup_meta() { setupMeta() {
Object.assign(this, require('./${utils.slug(name)}.json')); Object.assign(this, require('./${utils.slug(name)}.json'));
} }
} }

View File

@ -4,12 +4,12 @@ module.exports = {
async get_series_next(prefix) { async get_series_next(prefix) {
let series; let series;
try { try {
series = await frappe.get_doc('Number Series', prefix); series = await frappe.getDoc('Number Series', prefix);
} catch (e) { } catch (e) {
if (!e.status_code || e.status_code !== 404) { if (!e.status_code || e.status_code !== 404) {
throw e; throw e;
} }
series = frappe.new_doc({doctype: 'Number Series', name: prefix, current: 0}); series = frappe.newDoc({doctype: 'Number Series', name: prefix, current: 0});
await series.insert(); await series.insert();
} }
let next = await series.next() let next = await series.next()

View File

@ -8,8 +8,8 @@ module.exports = class BaseMeta extends BaseDocument {
this.list_options = { this.list_options = {
fields: ['name', 'modified'] fields: ['name', 'modified']
}; };
if (this.setup_meta) { if (this.setupMeta) {
this.setup_meta(); this.setupMeta();
} }
} }

View File

@ -2,7 +2,7 @@ const BaseMeta = require('frappejs/model/meta');
const BaseDocument = require('frappejs/model/document'); const BaseDocument = require('frappejs/model/document');
class NumberSeriesMeta extends BaseMeta { class NumberSeriesMeta extends BaseMeta {
setup_meta() { setupMeta() {
Object.assign(this, require('./number_series.json')); Object.assign(this, require('./number_series.json'));
} }
} }

View File

@ -2,7 +2,7 @@ const BaseMeta = require('frappejs/model/meta');
const BaseDocument = require('frappejs/model/document'); const BaseDocument = require('frappejs/model/document');
class RoleMeta extends BaseMeta { class RoleMeta extends BaseMeta {
setup_meta() { setupMeta() {
Object.assign(this, require('./role.json')); Object.assign(this, require('./role.json'));
} }
} }

View File

@ -2,13 +2,13 @@ const BaseMeta = require('frappejs/model/meta');
const BaseDocument = require('frappejs/model/document'); const BaseDocument = require('frappejs/model/document');
class SessionMeta extends BaseMeta { class SessionMeta extends BaseMeta {
setup_meta() { setupMeta() {
Object.assign(this, require('./session.json')); Object.assign(this, require('./session.json'));
} }
} }
class Session extends BaseDocument { class Session extends BaseDocument {
} }
module.exports = { module.exports = {

View File

@ -2,7 +2,7 @@ const BaseMeta = require('frappejs/model/meta');
const BaseDocument = require('frappejs/model/document'); const BaseDocument = require('frappejs/model/document');
class ToDoMeta extends BaseMeta { class ToDoMeta extends BaseMeta {
setup_meta() { setupMeta() {
Object.assign(this, require('./todo.json')); Object.assign(this, require('./todo.json'));
} }
} }

View File

@ -2,7 +2,7 @@ const BaseMeta = require('frappejs/model/meta');
const BaseDocument = require('frappejs/model/document'); const BaseDocument = require('frappejs/model/document');
class UserMeta extends BaseMeta { class UserMeta extends BaseMeta {
setup_meta() { setupMeta() {
Object.assign(this, require('./user.json')); Object.assign(this, require('./user.json'));
} }
} }

View File

@ -2,7 +2,7 @@ const BaseMeta = require('frappejs/model/meta');
const BaseDocument = require('frappejs/model/document'); const BaseDocument = require('frappejs/model/document');
class UserRoleMeta extends BaseMeta { class UserRoleMeta extends BaseMeta {
setup_meta() { setupMeta() {
Object.assign(this, require('./user_role.json')); Object.assign(this, require('./user_role.json'));
} }
} }

View File

@ -27,7 +27,7 @@ module.exports = {
app.post('/api/resource/:doctype', frappe.async_handler(async function(request, response) { app.post('/api/resource/:doctype', frappe.async_handler(async function(request, response) {
let data = request.body; let data = request.body;
data.doctype = request.params.doctype; data.doctype = request.params.doctype;
let doc = frappe.new_doc(data); let doc = frappe.newDoc(data);
await doc.insert(); await doc.insert();
await frappe.db.commit(); await frappe.db.commit();
return response.json(doc.getValidDict()); return response.json(doc.getValidDict());
@ -36,7 +36,7 @@ module.exports = {
// update // update
app.put('/api/resource/:doctype/:name', frappe.async_handler(async function(request, response) { app.put('/api/resource/:doctype/:name', frappe.async_handler(async function(request, response) {
let data = request.body; let data = request.body;
let doc = await frappe.get_doc(request.params.doctype, request.params.name); let doc = await frappe.getDoc(request.params.doctype, request.params.name);
Object.assign(doc, data); Object.assign(doc, data);
await doc.update(); await doc.update();
await frappe.db.commit(); await frappe.db.commit();
@ -46,7 +46,7 @@ module.exports = {
// get document // get document
app.get('/api/resource/:doctype/:name', frappe.async_handler(async function(request, response) { app.get('/api/resource/:doctype/:name', frappe.async_handler(async function(request, response) {
let doc = await frappe.get_doc(request.params.doctype, request.params.name); let doc = await frappe.getDoc(request.params.doctype, request.params.name);
return response.json(doc.getValidDict()); return response.json(doc.getValidDict());
})); }));
@ -58,7 +58,7 @@ module.exports = {
// delete // delete
app.delete('/api/resource/:doctype/:name', frappe.async_handler(async function(request, response) { app.delete('/api/resource/:doctype/:name', frappe.async_handler(async function(request, response) {
let doc = await frappe.get_doc(request.params.doctype, request.params.name) let doc = await frappe.getDoc(request.params.doctype, request.params.name)
await doc.delete(); await doc.delete();
return response.json({}); return response.json({});
})); }));
@ -67,7 +67,7 @@ module.exports = {
app.delete('/api/resource/:doctype', frappe.async_handler(async function(request, response) { app.delete('/api/resource/:doctype', frappe.async_handler(async function(request, response) {
let names = request.body; let names = request.body;
for (let name of names) { for (let name of names) {
let doc = await frappe.get_doc(request.params.doctype, name); let doc = await frappe.getDoc(request.params.doctype, name);
await doc.delete(); await doc.delete();
} }
return response.json({}); return response.json({});

View File

@ -8,7 +8,7 @@ describe('Controller', () => {
}); });
it('should call controller method', async () => { it('should call controller method', async () => {
let doc = frappe.new_doc({ let doc = frappe.newDoc({
doctype:'ToDo', doctype:'ToDo',
subject: 'test' subject: 'test'
}); });

View File

@ -14,7 +14,7 @@ describe('Document', () => {
await doc1.insert(); await doc1.insert();
// get it back from the db // get it back from the db
let doc2 = await frappe.get_doc(doc1.doctype, doc1.name); let doc2 = await frappe.getDoc(doc1.doctype, doc1.name);
assert.equal(doc1.subject, doc2.subject); assert.equal(doc1.subject, doc2.subject);
assert.equal(doc1.description, doc2.description); assert.equal(doc1.description, doc2.description);
@ -68,10 +68,10 @@ describe('Document', () => {
}); });
it('should add, fetch and delete documents with children', async() => { it('should add, fetch and delete documents with children', async() => {
await frappe.new_doc({doctype: 'Role', name: 'Test Role'}).insert(); await frappe.newDoc({doctype: 'Role', name: 'Test Role'}).insert();
await frappe.new_doc({doctype: 'Role', name: 'Test Role 1'}).insert(); await frappe.newDoc({doctype: 'Role', name: 'Test Role 1'}).insert();
let user = frappe.new_doc({ let user = frappe.newDoc({
doctype: 'User', doctype: 'User',
name: 'test_user', name: 'test_user',
full_name: 'Test User', full_name: 'Test User',
@ -105,7 +105,7 @@ describe('Document', () => {
await user.update(); await user.update();
user = await frappe.get_doc('User', user.name); user = await frappe.getDoc('User', user.name);
assert.equal(user.roles.length, 1); assert.equal(user.roles.length, 1);
assert.equal(user.roles[0].role, 'Test Role 1'); assert.equal(user.roles[0].role, 'Test Role 1');
@ -118,7 +118,7 @@ describe('Document', () => {
}); });
function test_doc() { function test_doc() {
return frappe.new_doc({ return frappe.newDoc({
doctype: 'ToDo', doctype: 'ToDo',
status: 'Open', status: 'Open',
subject: 'testing 1', subject: 'testing 1',

View File

@ -32,23 +32,23 @@ describe('REST', () => {
}); });
it('should create a document', async () => { it('should create a document', async () => {
let doc = frappe.new_doc({doctype:'ToDo', subject:'test rest insert 1'}); let doc = frappe.newDoc({doctype:'ToDo', subject:'test rest insert 1'});
await doc.insert(); await doc.insert();
let doc1 = await frappe.get_doc('ToDo', doc.name); let doc1 = await frappe.getDoc('ToDo', doc.name);
assert.equal(doc.subject, doc1.subject); assert.equal(doc.subject, doc1.subject);
assert.equal(doc1.status, 'Open'); assert.equal(doc1.status, 'Open');
}); });
it('should update a document', async () => { it('should update a document', async () => {
let doc = frappe.new_doc({doctype:'ToDo', subject:'test rest insert 1'}); let doc = frappe.newDoc({doctype:'ToDo', subject:'test rest insert 1'});
await doc.insert(); await doc.insert();
doc.subject = 'subject changed'; doc.subject = 'subject changed';
await doc.update(); await doc.update();
let doc1 = await frappe.get_doc('ToDo', doc.name); let doc1 = await frappe.getDoc('ToDo', doc.name);
assert.equal(doc.subject, doc1.subject); assert.equal(doc.subject, doc1.subject);
}); });
@ -63,7 +63,7 @@ describe('REST', () => {
}); });
it('should delete a document', async () => { it('should delete a document', async () => {
let doc = frappe.new_doc({doctype:'ToDo', subject:'test rest insert 1'}); let doc = frappe.newDoc({doctype:'ToDo', subject:'test rest insert 1'});
await doc.insert(); await doc.insert();
assert.equal(await frappe.db.exists(doc.doctype, doc.name), true); assert.equal(await frappe.db.exists(doc.doctype, doc.name), true);
@ -73,8 +73,8 @@ describe('REST', () => {
}); });
it('should delete multiple documents', async () => { it('should delete multiple documents', async () => {
let doc1 = frappe.new_doc({doctype:'ToDo', subject:'test rest insert 5'}); let doc1 = frappe.newDoc({doctype:'ToDo', subject:'test rest insert 5'});
let doc2 = frappe.new_doc({doctype:'ToDo', subject:'test rest insert 6'}); let doc2 = frappe.newDoc({doctype:'ToDo', subject:'test rest insert 6'});
await doc1.insert(); await doc1.insert();
await doc2.insert(); await doc2.insert();