Subscripting will give you a Collection<Document>. If you want to read the collection as a different (Codable) type you'll need to map the collection to a different type.
Insert returns a Future<Reply.Insert> which you can use to determine if one (or more) inserts failed. Is reply.ok != 1 the future will not be completed but failed with the reply, instead.
A range is any native swift Range. It is used for skip and limit.
+
// Cursor with the first 10 users
+
+letusers1=users.find(in:..<10)// Cursor<User>
+letusers2=users.find(in:10..<20)// Cursor<User>
+letusers3=users.find(in:30...)// Cursor<User>
+
The projection ensures only the specifies subset of fields are returned. Projections can also be computed fields. Remember that the projection must fit within the Collection's Codable type. If this is not a dictionary(-like) type such as Document it will be required that the Document fetched matches the Codable type.
Count is similar to a find operation in that it is a read-only operation. Since it does not return the actual data (only an integer of the total entities found) it does not support projections and sorting. It does support a range expression, although it's not often used.
In some situations you may find that MongoKitten's Database or ClientSettings are ambiguous with another library. The following lines will help get rid of that.
typealiasMongoDB=MongoKitten.Database
diff --git a/build/3.0/search/search_index.json b/build/3.0/search/search_index.json
index 1361e76b..5b2beb0f 100644
--- a/build/3.0/search/search_index.json
+++ b/build/3.0/search/search_index.json
@@ -1627,7 +1627,7 @@
},
{
"location": "/databases/mongodb/basics/",
- "text": "MongoDB Basics\n\u00b6\n\n\nimport MongoKitten\n in your file(s) using MongoKitten. This will automatically also import the \nBSON\n APIs.\n\n\nConnecting to MongoDB\n\u00b6\n\n\nTo connect to MongoDB you need to provide your connection URI and the database you want to access.\nThe database will also need access to your \nworker\n.\n\n\nlet\n \ndatabase\n \n=\n \nDatabase\n.\nconnect\n(\nserver\n:\n \n\"mongodb://localhost:27017\"\n,\n \ndatabase\n:\n \n\"test-db\"\n,\n \nworker\n:\n \nworker\n)\n \n// Future\n\n\n\n\n\n\nYou cannot use the connection globally. If you plan to use this connection globally you'll need to use a lock on it for querying since the connection is not thread safe. This will be added in a later stage of MongoKitten 5's beta.\n\n\nConnection as a Service\n\u00b6\n\n\nIf you want to use the connection within a Vapor 3 route you'll need to register this connection to your \nServices\n.\n\n\nservices\n.\nregister\n \n{\n \ncontainer\n \n->\n \nClientSettings\n \nin\n\n \nreturn\n \n\"mongodb://localhost:27017\"\n \n// Your MongoDB URI here\n\n\n}\n\n\n\nservices\n.\nregister\n \n{\n \ncontainer\n \n->\n \nDatabase\n \nin\n\n \nlet\n \nserver\n \n=\n \ntry\n \ncontainer\n.\nmake\n(\nClientSettings\n.\nself\n,\n \nfor\n:\n \nDatabase\n.\nself\n)\n\n\n \n// Future\n\n \nlet\n \ndb\n \n=\n \ntry\n \nDatabase\n.\nconnect\n(\nsever\n:\n \nserver\n,\n \ndatabase\n:\n \n\"my-database\"\n,\n \nworker\n:\n \ncontainer\n)\n\n\n \n// Await here, it doesn't hurt performant much and it only needs to wait once per worker\n\n \nreturn\n \ntry\n \ndb\n.\nawait\n(\non\n:\n \ncontainer\n)\n\n\n}\n\n\n\n\n\n\nCRUD\n\u00b6\n\n\nBefore applying a CRUD operation you need to select a Collection first. This is the MongoDB equivalent of a table.\n\n\nYou can subscript a database with a string to get a collection with that name. You do not need to set up a schema first.\n\n\nrouter\n.\nget\n(\n\"users\"\n)\n \n{\n \nrequest\n \nin\n\n \nlet\n \ndatabase\n \n=\n \ntry\n \nrequest\n.\nmake\n(\nDatabase\n.\nself\n)\n\n \nlet\n \nusers\n \n=\n \ndatabase\n[\n\"users\"\n]\n\n\n \n...\n\n\n}\n\n\n\n\n\n\nCreating\n\u00b6\n\n\n\n\n\n\n\n\nTroubleshooting\n\u00b6\n\n\nAmbiguous naming\n\u00b6\n\n\nIn some situations you may find that MongoKitten's \nDatabase\n or \nClientSettings\n are ambiguous with another library. The following lines will help get rid of that.\n\n\ntypealias\n \nMongoDB\n \n=\n \nMongoKitten\n.\nDatabase\n\n\ntypealias\n \nMongoDBSettings\n \n=\n \nMongoKitten\n.\nClientSettings\n\n\n\n\n\n\nIn the above case you'll have to use the aliases instead of the normal references to \nDatabase\n and/or \nClientSettings\n. Alternatively you can prefix the occurences of those instances with \nMongoKitten.\n, indicating you want the \nDatabase\n object of the MongoKitten module.",
+ "text": "MongoDB Basics\n\u00b6\n\n\nimport MongoKitten\n in your file(s) using MongoKitten. This will automatically also import the \nBSON\n APIs.\n\n\nConnecting to MongoDB\n\u00b6\n\n\nTo connect to MongoDB you need to provide your connection URI and the database you want to access.\nThe database will also need access to your \nworker\n.\n\n\nlet\n \ndatabase\n \n=\n \nDatabase\n.\nconnect\n(\nserver\n:\n \n\"mongodb://localhost:27017\"\n,\n \ndatabase\n:\n \n\"test-db\"\n,\n \nworker\n:\n \nworker\n)\n \n// Future\n\n\n\n\n\n\nYou cannot use the connection globally. If you plan to use this connection globally you'll need to use a lock on it for querying since the connection is not thread safe. This will be added in a later stage of MongoKitten 5's beta.\n\n\nConnection as a Service\n\u00b6\n\n\nIf you want to use the connection within a Vapor 3 route you'll need to register this connection to your \nServices\n.\n\n\nservices\n.\nregister\n \n{\n \ncontainer\n \n->\n \nClientSettings\n \nin\n\n \nreturn\n \n\"mongodb://localhost:27017\"\n \n// Your MongoDB URI here\n\n\n}\n\n\n\nservices\n.\nregister\n \n{\n \ncontainer\n \n->\n \nDatabase\n \nin\n\n \nlet\n \nserver\n \n=\n \ntry\n \ncontainer\n.\nmake\n(\nClientSettings\n.\nself\n,\n \nfor\n:\n \nDatabase\n.\nself\n)\n\n\n \n// Future\n\n \nlet\n \ndb\n \n=\n \ntry\n \nDatabase\n.\nconnect\n(\nsever\n:\n \nserver\n,\n \ndatabase\n:\n \n\"my-database\"\n,\n \nworker\n:\n \ncontainer\n)\n\n\n \n// Await here, it doesn't hurt performant much and it only needs to wait once per worker\n\n \nreturn\n \ntry\n \ndb\n.\nawait\n(\non\n:\n \ncontainer\n)\n\n\n}\n\n\n\n\n\n\nCRUD\n\u00b6\n\n\nBefore applying a CRUD operation you need to select a Collection first. This is the MongoDB equivalent of a table.\n\n\nYou can subscript a database with a string to get a collection with that name. You do not need to set up a schema first.\n\n\nrouter\n.\nget\n(\n\"users\"\n)\n \n{\n \nrequest\n \nin\n\n \nlet\n \ndatabase\n \n=\n \ntry\n \nrequest\n.\nmake\n(\nDatabase\n.\nself\n)\n\n \nlet\n \nusers\n \n=\n \ndatabase\n[\n\"users\"\n]\n \n// Collection\n\n\n \n...\n\n\n}\n\n\n\n\n\n\nSubscripting will give you a \nCollection\n. If you want to read the collection as a different (Codable) type you'll need to \nmap\n the collection to a different type.\n\n\nstruct\n \nUser\n:\n \nCodable\n \n{\n\n \nvar\n \n_id\n \n=\n \nObjectId\n()\n\n \nvar\n \nusername\n:\n \nString\n\n \nvar\n \nage\n:\n \nInt\n\n\n \ninit\n(\nnamed\n \nname\n:\n \nString\n,\n \nage\n:\n \nInt\n)\n \n{\n\n \nself\n.\nusername\n \n=\n \nnamed\n\n \nself\n.\nage\n \n=\n \nage\n\n \n}\n\n\n}\n\n\n\nlet\n \nusers\n \n=\n \ndatabase\n[\n\"users\"\n].\nmap\n(\nto\n:\n \nUser\n.\nself\n)\n\n\n\n\n\n\nCRUD operations\n\n\nInsert\n\u00b6\n\n\nInserting entities is done by using \n.insert\n with either one or a sequence of the entity.\n\n\nusers\n.\ninsert\n(\nuser\n)\n\n\nusers\n.\ninsertAll\n([\nuser1\n,\n \nuser2\n,\n \nuser3\n])\n\n\n\n\n\n\nInsert returns a \nFuture\n which you can use to determine if one (or more) inserts failed. Is \nreply.ok != 1\n the future will not be completed but failed with the reply, instead.\n\n\nlet\n \nreply\n \n=\n \nusers\n.\ninsertAll\n([\nuser1\n,\n \nuser2\n,\n \nuser3\n])\n\n\n\nreply\n.\ndo\n \n{\n \nsuccess\n \nin\n\n \nprint\n(\n\"\n\\(\nsuccess\n.\nn\n)\n users inserted\"\n)\n\n\n}.\ncatch\n \n{\n \nerror\n \nin\n\n \n// Insert failed!\n\n\n}\n\n\n\n\n\n\nFind\n\u00b6\n\n\nUsing \nfind\n on a collection returns a \nCursor\n where \nC\n is the type nested in the collection as demonstrated above.\n\n\nfind\n can take 4 arguments. A filter, range, sort and projection.\n\n\nThere is also \nfindOne\n, which is useful when you want to exactly one object. This does not support a range expression.\n\n\nFilter\n\u00b6\n\n\nThe filter is a MongoKitten \nQuery\n object.\n\n\n// User?\n\n\nguard\n \nlet\n \njoannis\n \n=\n \nusers\n.\nfindOne\n(\n\"username\"\n \n==\n \n\"Joannis\"\n \n&&\n \n\"active\"\n \n==\n \ntrue\n)\n \nelse\n \n{\n\n \nreturn\n\n\n}\n\n\n\n\n\n\nRange\n\u00b6\n\n\nA range is any native swift Range. It is used for \nskip\n and \nlimit\n.\n\n\n// Cursor with the first 10 users\n\n\n\nlet\n \nusers1\n \n=\n \nusers\n.\nfind\n(\nin\n:\n \n..<\n10\n)\n \n// Cursor\n\n\nlet\n \nusers2\n \n=\n \nusers\n.\nfind\n(\nin\n:\n \n10.\n.<\n20\n)\n \n// Cursor\n\n\nlet\n \nusers3\n \n=\n \nusers\n.\nfind\n(\nin\n:\n \n30.\n..)\n \n// Cursor\n\n\n\n\n\n\nSort\n\u00b6\n\n\nThe \nSort\n is used to sort entities in either ascending or descending order based on one or more fields.\n\n\nlet\n \nmaleUsers\n \n=\n \nusers\n.\nfind\n(\n\"gender\"\n \n==\n \n\"male\"\n,\n \nsortedBy\n:\n \n[\n\"age\"\n:\n \n.\nascending\n])\n \n// Cursor\n\n\n\n\n\n\nProjection\n\u00b6\n\n\nThe \nprojection\n ensures only the specifies subset of fields are returned. Projections can also be computed fields. Remember that the projection must fit within the Collection's Codable type. If this is not a dictionary(-like) type such as \nDocument\n it will be required that the Document fetched matches the Codable type.\n\n\nlet\n \nadults\n \n=\n \nusers\n.\nfind\n(\n\"age\"\n \n>=\n \n21\n,\n \nprojecting\n:\n \n[\n\"_id\"\n:\n \n.\nexcluded\n,\n \n\"username\"\n:\n \n.\nincluded\n])\n \n// Cursor\n\n\n\n\n\n\nCount\n\u00b6\n\n\nCount is similar to a find operation in that it is a read-only operation. Since it does not return the actual data (only an integer of the total entities found) it does not support projections and sorting. It does support a range expression, although it's not often used.\n\n\nlet\n \ntotalUsers\n \n=\n \nusers\n.\ncount\n()\n \n// Future\n\n\nlet\n \nfemaleUsers\n \n=\n \nusers\n.\ncount\n(\n\"gender\"\n \n==\n \n\"female\"\n)\n \n// Future\n\n\n\n\n\n\nUpdate\n\u00b6\n\n\nUpdating can be done on one or all entities. Updates can either update the entire entity or only a subset of fields.\n\n\nlet\n \nuser\n \n=\n \nUser\n(\nnamed\n:\n \n\"Joannis\"\n,\n \nage\n:\n \n111\n)\n\n\n\nusers\n.\nupdate\n(\n\"username\"\n \n==\n \n\"Joannis\"\n,\n \nto\n:\n \nuser\n)\n\n\n\n\n\n\nUpdate also indicates a success state in the same way \ninsert\n does.\n\n\nUpdating fields\n\u00b6\n\n\nUpdating a subset of fields can be done more efficiently using\n\n\n// Rename `Joannis` -> `JoannisO`\n\n\nusers\n.\nupdate\n(\n\"username\"\n \n==\n \n\"Joannis\"\n,\n \nfields\n:\n \n[\n\n \n\"username\"\n:\n \n\"JoannisO\"\n\n\n])\n\n\n\n// Migrate all users to require a password update\n\n\nusers\n.\nupdate\n(\nfields\n:\n \n[\n\n \n\"resetPassword\"\n:\n \ntrue\n\n\n])\n\n\n\n\n\n\nUpsert\n\u00b6\n\n\nIf you don't know if an entity exists but want it inserted/updated accordingly you should use \nupsert\n.\n\n\nlet\n \nuser\n \n=\n \nUser\n(\nnamed\n:\n \n\"Joannis\"\n,\n \nage\n:\n \n111\n)\n\n\n\nusers\n.\nupsert\n(\n\"_id\"\n \n==\n \nuser\n.\n_id\n,\n \nto\n:\n \nuser\n)\n\n\n\n\n\n\nRemove\n\u00b6\n\n\nRemove removes the first or all entities matching a query.\n\n\n// Remove me!\n\n\nusers\n.\nremove\n(\n\"username\"\n \n==\n \n\"Joannis\"\n)\n\n\n\n// Remove all Dutch users\n\n\nusers\n.\nremoveAll\n(\n\"country\"\n \n==\n \n\"NL\"\n)\n\n\n\n\n\n\nTroubleshooting\n\u00b6\n\n\nAmbiguous naming\n\u00b6\n\n\nIn some situations you may find that MongoKitten's \nDatabase\n or \nClientSettings\n are ambiguous with another library. The following lines will help get rid of that.\n\n\ntypealias\n \nMongoDB\n \n=\n \nMongoKitten\n.\nDatabase\n\n\ntypealias\n \nMongoDBSettings\n \n=\n \nMongoKitten\n.\nClientSettings\n\n\n\n\n\n\nIn the above case you'll have to use the aliases instead of the normal references to \nDatabase\n and/or \nClientSettings\n. Alternatively you can prefix the occurences of those instances with \nMongoKitten.\n, indicating you want the \nDatabase\n object of the MongoKitten module.",
"title": "Basics"
},
{
@@ -1647,13 +1647,63 @@
},
{
"location": "/databases/mongodb/basics/#crud",
- "text": "Before applying a CRUD operation you need to select a Collection first. This is the MongoDB equivalent of a table. You can subscript a database with a string to get a collection with that name. You do not need to set up a schema first. router . get ( \"users\" ) { request in \n let database = try request . make ( Database . self ) \n let users = database [ \"users\" ] \n\n ... }",
+ "text": "Before applying a CRUD operation you need to select a Collection first. This is the MongoDB equivalent of a table. You can subscript a database with a string to get a collection with that name. You do not need to set up a schema first. router . get ( \"users\" ) { request in \n let database = try request . make ( Database . self ) \n let users = database [ \"users\" ] // Collection \n\n ... } Subscripting will give you a Collection . If you want to read the collection as a different (Codable) type you'll need to map the collection to a different type. struct User : Codable { \n var _id = ObjectId () \n var username : String \n var age : Int \n\n init ( named name : String , age : Int ) { \n self . username = named \n self . age = age \n } } let users = database [ \"users\" ]. map ( to : User . self ) CRUD operations",
"title": "CRUD"
},
{
- "location": "/databases/mongodb/basics/#creating",
- "text": "",
- "title": "Creating"
+ "location": "/databases/mongodb/basics/#insert",
+ "text": "Inserting entities is done by using .insert with either one or a sequence of the entity. users . insert ( user ) users . insertAll ([ user1 , user2 , user3 ]) Insert returns a Future which you can use to determine if one (or more) inserts failed. Is reply.ok != 1 the future will not be completed but failed with the reply, instead. let reply = users . insertAll ([ user1 , user2 , user3 ]) reply . do { success in \n print ( \" \\( success . n ) users inserted\" ) }. catch { error in \n // Insert failed! }",
+ "title": "Insert"
+ },
+ {
+ "location": "/databases/mongodb/basics/#find",
+ "text": "Using find on a collection returns a Cursor where C is the type nested in the collection as demonstrated above. find can take 4 arguments. A filter, range, sort and projection. There is also findOne , which is useful when you want to exactly one object. This does not support a range expression.",
+ "title": "Find"
+ },
+ {
+ "location": "/databases/mongodb/basics/#filter",
+ "text": "The filter is a MongoKitten Query object. // User? guard let joannis = users . findOne ( \"username\" == \"Joannis\" && \"active\" == true ) else { \n return }",
+ "title": "Filter"
+ },
+ {
+ "location": "/databases/mongodb/basics/#range",
+ "text": "A range is any native swift Range. It is used for skip and limit . // Cursor with the first 10 users let users1 = users . find ( in : ..< 10 ) // Cursor let users2 = users . find ( in : 10. .< 20 ) // Cursor let users3 = users . find ( in : 30. ..) // Cursor",
+ "title": "Range"
+ },
+ {
+ "location": "/databases/mongodb/basics/#sort",
+ "text": "The Sort is used to sort entities in either ascending or descending order based on one or more fields. let maleUsers = users . find ( \"gender\" == \"male\" , sortedBy : [ \"age\" : . ascending ]) // Cursor",
+ "title": "Sort"
+ },
+ {
+ "location": "/databases/mongodb/basics/#projection",
+ "text": "The projection ensures only the specifies subset of fields are returned. Projections can also be computed fields. Remember that the projection must fit within the Collection's Codable type. If this is not a dictionary(-like) type such as Document it will be required that the Document fetched matches the Codable type. let adults = users . find ( \"age\" >= 21 , projecting : [ \"_id\" : . excluded , \"username\" : . included ]) // Cursor",
+ "title": "Projection"
+ },
+ {
+ "location": "/databases/mongodb/basics/#count",
+ "text": "Count is similar to a find operation in that it is a read-only operation. Since it does not return the actual data (only an integer of the total entities found) it does not support projections and sorting. It does support a range expression, although it's not often used. let totalUsers = users . count () // Future let femaleUsers = users . count ( \"gender\" == \"female\" ) // Future",
+ "title": "Count"
+ },
+ {
+ "location": "/databases/mongodb/basics/#update",
+ "text": "Updating can be done on one or all entities. Updates can either update the entire entity or only a subset of fields. let user = User ( named : \"Joannis\" , age : 111 ) users . update ( \"username\" == \"Joannis\" , to : user ) Update also indicates a success state in the same way insert does.",
+ "title": "Update"
+ },
+ {
+ "location": "/databases/mongodb/basics/#updating-fields",
+ "text": "Updating a subset of fields can be done more efficiently using // Rename `Joannis` -> `JoannisO` users . update ( \"username\" == \"Joannis\" , fields : [ \n \"username\" : \"JoannisO\" ]) // Migrate all users to require a password update users . update ( fields : [ \n \"resetPassword\" : true ])",
+ "title": "Updating fields"
+ },
+ {
+ "location": "/databases/mongodb/basics/#upsert",
+ "text": "If you don't know if an entity exists but want it inserted/updated accordingly you should use upsert . let user = User ( named : \"Joannis\" , age : 111 ) users . upsert ( \"_id\" == user . _id , to : user )",
+ "title": "Upsert"
+ },
+ {
+ "location": "/databases/mongodb/basics/#remove",
+ "text": "Remove removes the first or all entities matching a query. // Remove me! users . remove ( \"username\" == \"Joannis\" ) // Remove all Dutch users users . removeAll ( \"country\" == \"NL\" )",
+ "title": "Remove"
},
{
"location": "/databases/mongodb/basics/#troubleshooting",
diff --git a/build/3.0/site/404.html b/build/3.0/site/404.html
deleted file mode 100644
index b36d6a53..00000000
--- a/build/3.0/site/404.html
+++ /dev/null
@@ -1,1431 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Vapor Docs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
404 - Not found
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/build/3.0/site/assets/images/favicon.ico b/build/3.0/site/assets/images/favicon.ico
deleted file mode 100644
index e85006a3..00000000
Binary files a/build/3.0/site/assets/images/favicon.ico and /dev/null differ
diff --git a/build/3.0/site/assets/images/icons/bitbucket-670608a71a.svg b/build/3.0/site/assets/images/icons/bitbucket-670608a71a.svg
deleted file mode 100644
index 7d95cb22..00000000
--- a/build/3.0/site/assets/images/icons/bitbucket-670608a71a.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/build/3.0/site/assets/images/icons/github-1da075986e.svg b/build/3.0/site/assets/images/icons/github-1da075986e.svg
deleted file mode 100644
index 3cacb2e0..00000000
--- a/build/3.0/site/assets/images/icons/github-1da075986e.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/build/3.0/site/assets/images/icons/gitlab-5ad3f9f9e5.svg b/build/3.0/site/assets/images/icons/gitlab-5ad3f9f9e5.svg
deleted file mode 100644
index b036a9b5..00000000
--- a/build/3.0/site/assets/images/icons/gitlab-5ad3f9f9e5.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/build/3.0/site/assets/javascripts/application-8e4952e681.js b/build/3.0/site/assets/javascripts/application-8e4952e681.js
deleted file mode 100644
index 49fe7d1b..00000000
--- a/build/3.0/site/assets/javascripts/application-8e4952e681.js
+++ /dev/null
@@ -1 +0,0 @@
-window.app=function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=35)}([function(e,t,n){"use strict";var r=n(23)("wks"),i=n(14),o=n(1).Symbol,a="function"==typeof o;(e.exports=function(e){return r[e]||(r[e]=a&&o[e]||(a?o:i)("Symbol."+e))}).store=r},function(e,t,n){"use strict";var r=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=r)},function(e,t,n){"use strict";var r=n(10),i=n(25);e.exports=n(5)?function(e,t,n){return r.f(e,t,i(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){"use strict";var r=n(11);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t,n){"use strict";var r=n(1),i=n(2),o=n(6),a=n(14)("src"),s=Function.toString,c=(""+s).split("toString");n(7).inspectSource=function(e){return s.call(e)},(e.exports=function(e,t,n,s){var u="function"==typeof n;u&&(o(n,"name")||i(n,"name",t)),e[t]!==n&&(u&&(o(n,a)||i(n,a,e[t]?""+e[t]:c.join(String(t)))),e===r?e[t]=n:s?e[t]?e[t]=n:i(e,t,n):(delete e[t],i(e,t,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[a]||s.call(this)})},function(e,t,n){"use strict";e.exports=!n(24)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){"use strict";var r={}.hasOwnProperty;e.exports=function(e,t){return r.call(e,t)}},function(e,t,n){"use strict";var r=e.exports={version:"2.4.0"};"number"==typeof __e&&(__e=r)},function(e,t,n){"use strict";e.exports={}},function(e,t,n){"use strict";var r={}.toString;e.exports=function(e){return r.call(e).slice(8,-1)}},function(e,t,n){"use strict";var r=n(3),i=n(38),o=n(39),a=Object.defineProperty;t.f=n(5)?Object.defineProperty:function(e,t,n){if(r(e),t=o(t,!0),r(n),i)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};e.exports=function(e){return"object"===(void 0===e?"undefined":r(e))?null!==e:"function"==typeof e}},function(e,t,n){"use strict";var r=n(18);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}}},function(e,t,n){"use strict";var r=n(9),i=n(0)("toStringTag"),o="Arguments"==r(function(){return arguments}()),a=function(e,t){try{return e[t]}catch(e){}};e.exports=function(e){var t,n,s;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=a(t=Object(e),i))?n:o?r(t):"Object"==(s=r(t))&&"function"==typeof t.callee?"Arguments":s}},function(e,t,n){"use strict";var r=0,i=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++r+i).toString(36))}},function(e,t,n){"use strict";var r=n(11),i=n(1).document,o=r(i)&&r(i.createElement);e.exports=function(e){return o?i.createElement(e):{}}},function(e,t,n){"use strict";var r=Math.ceil,i=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?i:r)(e)}},function(e,t,n){"use strict";e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){"use strict";e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t,n){"use strict";var r=n(47),i=n(17);e.exports=function(e){return r(i(e))}},function(e,t,n){"use strict";var r=n(23)("keys"),i=n(14);e.exports=function(e){return r[e]||(r[e]=i(e))}},function(e,t,n){"use strict";var r=n(10).f,i=n(6),o=n(0)("toStringTag");e.exports=function(e,t,n){e&&!i(e=n?e:e.prototype,o)&&r(e,o,{configurable:!0,value:t})}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={createElement:function(e,t){var n=document.createElement(e);t&&Array.prototype.forEach.call(Object.keys(t),function(e){n.setAttribute(e,t[e])});for(var r=arguments.length,i=Array(r>2?r-2:0),o=2;o0?i(r(e),9007199254740991):0}},function(e,t,n){"use strict";e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){"use strict";e.exports=n(1).document&&document.documentElement},function(e,t,n){"use strict";var r,i,o,a=n(12),s=n(63),c=n(31),u=n(15),l=n(1),f=l.process,h=l.setImmediate,d=l.clearImmediate,p=l.MessageChannel,m=0,y={},v=function(){var e=+this;if(y.hasOwnProperty(e)){var t=y[e];delete y[e],t()}},g=function(e){v.call(e.data)};h&&d||(h=function(e){for(var t=[],n=1;arguments.length>n;)t.push(arguments[n++]);return y[++m]=function(){s("function"==typeof e?e:Function(e),t)},r(m),m},d=function(e){delete y[e]},"process"==n(9)(f)?r=function(e){f.nextTick(a(v,e,1))}:p?(i=new p,o=i.port2,i.port1.onmessage=g,r=a(o.postMessage,o,1)):l.addEventListener&&"function"==typeof postMessage&&!l.importScripts?(r=function(e){l.postMessage(e+"","*")},l.addEventListener("message",g,!1)):r="onreadystatechange"in u("script")?function(e){c.appendChild(u("script")).onreadystatechange=function(){c.removeChild(this),v.call(e)}}:function(e){setTimeout(a(v,e,1),0)}),e.exports={set:h,clear:d}},function(e,t){(function(t){e.exports=t}).call(t,{})},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var i=function(){function e(e,t){for(var n=0;n=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t,n){"use strict";var r=n(16),i=n(17);e.exports=function(e){return function(t,n){var o,a,s=String(i(t)),c=r(n),u=s.length;return c<0||c>=u?e?"":void 0:(o=s.charCodeAt(c),o<55296||o>56319||c+1===u||(a=s.charCodeAt(c+1))<56320||a>57343?e?s.charAt(c):o:e?s.slice(c,c+2):a-56320+(o-55296<<10)+65536)}}},function(e,t,n){"use strict";var r=n(43),i=n(25),o=n(21),a={};n(2)(a,n(0)("iterator"),function(){return this}),e.exports=function(e,t,n){e.prototype=r(a,{next:i(1,n)}),o(e,t+" Iterator")}},function(e,t,n){"use strict";var r=n(3),i=n(44),o=n(30),a=n(20)("IE_PROTO"),s=function(){},c=function(){var e,t=n(15)("iframe"),r=o.length;for(t.style.display="none",n(31).appendChild(t),t.src="javascript:",e=t.contentWindow.document,e.open(),e.write("
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Event loops are at the heart of Vapor's non-blocking concurrency model. There is usually one event loop per logical core in your computer's CPU. The event loop's main purpose is to detect when data is ready to be read from or written to a socket. By detecting socket events before actually attempting to read or write data, Vapor can avoid making function calls that may block. Avoiding blocking calls is critical for performance as it allows Vapor to aggressively re-use threads, making your app very fast and efficient.
-
In addition to the above, they're also able to run single tasks inbetween listening for events.
-
There are three main forms of eventloops.
-
DispatchEventLoop is based on Dispatch, KQueueEventLoop is a macOS-only eventloop that is more performant than Dispatch.
-
The third one (currently work in progress) is the EPollEventLoop, a Linux only eventloop that is also more performant than Dispatch.
It is likely that we'll start inferring the current EventLoop using the Thread Local Storage, removing the need for Workers and passing EventLoop as an argument.
To add/remove listeners from EventLoops you can ask for a readable or writable source or EventSource. EventSources are a handle which can be resumed, suspended and cancelled.
-When requesting said handle on an EventLoop you must provide a closure which calls back with the notification.
-
This notification indicates that data is available for work in the provided descriptor. This includes the descriptor being closed.
Write sources are the opposite of a Source in that they notify the ability to write data. They should be suspended after the first write so that they do not call back every loop.
-
Whilst Sources indicate the availability of data, Drains
As part of the EventLoops in Vapor 3, we also centralized the asynchronous part of Sockets, simplifying the APIs for I/O and improving it's asynchronous usability. It is recommended for (raw) TCP, (raw) UDP and SSL implementations to conform to the Socket protocol.
SocketSink is a helper that assists with writing data to sockets reactively.
-SocketSource is a helper that functions as the Sink's counterpart with reading data from sockets reactively.