diff --git a/404.html b/404.html index 885e1e99..4f335e08 100644 --- a/404.html +++ b/404.html @@ -13,7 +13,7 @@ - +
diff --git a/assets/js/50ac8df9.3f905d6d.js b/assets/js/50ac8df9.300fecc8.js similarity index 98% rename from assets/js/50ac8df9.3f905d6d.js rename to assets/js/50ac8df9.300fecc8.js index 11e86e1a..f3be5553 100644 --- a/assets/js/50ac8df9.3f905d6d.js +++ b/assets/js/50ac8df9.300fecc8.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5180],{13146:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>r,contentTitle:()=>l,default:()=>m,frontMatter:()=>s,metadata:()=>c,toc:()=>a});var o=t(11527),i=t(63883);const s={},l="Relations",c={id:"composedb/guides/data-modeling/relations",title:"Relations",description:"Define queryable relationships between models and other models or accounts.",source:"@site/docs/composedb/guides/data-modeling/relations.mdx",sourceDirName:"composedb/guides/data-modeling",slug:"/composedb/guides/data-modeling/relations",permalink:"/docs/composedb/guides/data-modeling/relations",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Schemas",permalink:"/docs/composedb/guides/data-modeling/schemas"},next:{title:"Composites",permalink:"/docs/composedb/guides/data-modeling/composites"}},r={},a=[{value:"Types of Relations",id:"types-of-relations",level:2},{value:"Account to Model",id:"account-to-model",level:2},{value:"Example: Simple Profile",id:"example-simple-profile",level:3},{value:"Model to Account",id:"model-to-account",level:2},{value:"Example: Direct message (DM)",id:"example-direct-message-dm",level:3},{value:"Model to Model",id:"model-to-model",level:2},{value:"Example: Post with comments and likes",id:"example-post-with-comments-and-likes",level:3},{value:"Using interfaces",id:"using-interfaces",level:3},{value:"Account to Account",id:"account-to-account",level:2},{value:"Next Steps",id:"next-steps",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"relations",children:"Relations"}),"\n",(0,o.jsx)(n.p,{children:"Define queryable relationships between models and other models or accounts."}),"\n",(0,o.jsx)(n.h2,{id:"types-of-relations",children:"Types of Relations"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.p,{children:"There are a few primary forms of relations currently supported by ComposeDB:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#account-to-model",children:"Account to model relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#model-to-account",children:"Model to account relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#model-to-model",children:"Model to model relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#account-to-account",children:"Account to account relations"})}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"account-to-model",children:"Account to Model"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Account to model relations enable linking and querying data to the account that created it. By default the ",(0,o.jsx)(n.code,{children:"@createmodel"})," directive (used when creating a new model) requires that every model must specify a relation to its author\u2019s account. This was covered in ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"}),"."]}),"\n",(0,o.jsx)(n.h3,{id:"example-simple-profile",children:"Example: Simple Profile"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model for a very simple user profile that can be queried based on the author:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Define simple profile model\n# Relate it to the author\'s account\n# Limit to one profile per account\n# Enable queries based on author\n\ntype SimpleProfile @createModel(accountRelation: SINGLE, description: "Very basic profile") {\n displayName: String! @string(minLength: 3, maxLength: 50)\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"accountRelation"})," relates the profile to the author\u2019s account"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"SINGLE"})," limits to one profile per account"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"model-to-account",children:"Model to Account"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Model to account relations enable you to link data to and query data from an account other than the data\u2019s author. When using this type of relation, you need to define a model field that stores an account (e.g. a ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/composedb-client/user-sessions",children:"DID"}),"), then add the ",(0,o.jsx)(n.code,{children:"@accountReference"})," directive to make it queryable."]}),"\n",(0,o.jsx)(n.h3,{id:"example-direct-message-dm",children:"Example: Direct message (DM)"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model for a user-to-user message that can be queried based on the recipient:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:"# Define message model\n# Relate it to author's account\n# Allow unlimited sent messages\n# Store reference to recipient's account\n# Enable queries based on recipient\n\ntype Message @createModel(accountRelation: LIST, description: \"Direct message model\") {\n recipient: DID! @accountReference\n directMessage: String! @string(minLength: 1, maxLength: 200)\n}\n"})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"accountRelation"})," relates the message to the author\u2019s account"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"LIST"})," allows unlimited messages"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"recipient"})," references the recipient\u2019s account by storing its ",(0,o.jsx)(n.code,{children:"DID!"}),", using ",(0,o.jsx)(n.code,{children:"@accountReference"})]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"model-to-model",children:"Model to Model"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.p,{children:"Model to model relations enable you to link data to and query data from another piece of data. These relations can be uni-directional (e.g. query a post from a comment) or bi-directional (e.g. query a post from a comment and query all comments from a post)."}),"\n",(0,o.jsxs)(n.p,{children:["There is type of model-to-model relation that includes the user as part of the relationship. This is achieved by using the ",(0,o.jsx)(n.code,{children:"SET"})," account relation type, which allows users to enforce a constraint where each user account (or DID) can create only one instance of a model for a specific record of another model."]}),"\n",(0,o.jsx)(n.h3,{id:"example-post-with-comments-and-likes",children:"Example: Post with comments and likes"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model that allows many comments from the same or different account to be made on a single post. It supports unlimited comments per user, and bi-directional queries from any comment or like to the original post and from the original post to all of its comments and likes. The model schema also creates a relation between posts and likes enabling a single like per post by an account, meaning a single account will only be able to like the post once"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Load post model (using streamID)\n\ntype Post @loadModel(id: "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96") {\n id: ID!\n}\n\n# New comment model\n# Set reference to original post\n# Enable querying comment to get original post\n\ntype Comment @createModel(accountRelation: LIST, description: "A comment on a Post") {\n postID: StreamID! @documentReference(model: "Post")\n post: Post! @relationDocument(property: "postID")\n text: String! @string(maxLength: 500)\n}\n\n# New like model\n# Set relationship to original post\n# Enable querying comment to get original post\ntype Like @createModel(description: "A like on a post", accountRelation: SET, accountRelationFields: ["postID"]) {\n postID: StreamID! @documentReference(model: "Post")\n post: Post! @relationDocument(property: "postID")\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Relations can also be created between models loaded from known streamIDs"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Load comment model\n\ntype Comment @loadModel(id: "kjzl6hvfrbw6c9oo2ync09y6z5c9mas9u49lfzcowepuzxmcn3pzztvzd0c7gh0") {\n id: ID!\n}\n\n# Load post model\n# Extend post model with comments and likes\n# Set relationships to all comments and likes\n# Enable querying post to get all comments and likes\n\ntype Post @loadModel(id: "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96") {\n comments: [Comment] @relationFrom(model: "Comment", property: "postID")\n likes: [Like] @relationFrom(model: "Like", property: "postID")\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"id"})," is a simple placeholder, since empty types are not allowed"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"postID"})," defines the relationship from a comment to the original post, using ",(0,o.jsx)(n.code,{children:"@documentReference"})]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"post"})," allows accessing the original post from the comment, using ",(0,o.jsx)(n.code,{children:"@relationDocument"})]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"text"})," defines a string for the comment"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"comments"})," defines the relationships from a post to a collection of comments, using ",(0,o.jsx)(n.code,{children:"@relationFrom"}),"; requires specifying the model relation (",(0,o.jsx)(n.code,{children:"Comment"}),") and the specific property that stores the relation (",(0,o.jsx)(n.code,{children:"postID"}),")"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"likes"})," defines the relationships from a post to a collection of comments, using ",(0,o.jsx)(n.code,{children:"@relationFrom"}),"; requires specifying the model relation (",(0,o.jsx)(n.code,{children:"Like"}),") and the specific property that stores the relation (",(0,o.jsx)(n.code,{children:"postID"}),")"]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"using-interfaces",children:"Using interfaces"}),"\n",(0,o.jsx)(n.p,{children:"When defining relations, it is possible to reference model interfaces to allow for a wider range of documents in the relations set, for example to create a collection of documents using different models implementing the same interface:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'interface TextContent @createModel(description: "Required text content interface") {\n text: String! @string(maxLength: 10000)\n}\n\ntype Page implements TextContent @createModel(description: "Page model") {\n title: String @string(maxLength: 100)\n text: String! @string(maxLength: 10000)\n}\n\ntype Post implements TextContent @createModel(description: "Post model") {\n title: String! @string(maxLength: 100)\n text: String! @string(maxLength: 10000)\n createdAt: DateTime!\n}\n\ntype ContentCollectionItem\n @createModel(description: "Association between a collection and an item") {\n # The Node interface is used here instead of ContentCollection, see warning below\n collectionID: StreamID! @documentReference(model: "Node")\n collection: Node! @relationDocument(property: "collectionID")\n itemID: StreamID! @documentReference(model: "TextContent")\n item: TextContent! @relationDocument(property: "itemID")\n}\n\ntype ContentCollection @createModel(description: "Collection of text contents") {\n name: String @string(maxLength: 50)\n items: [ContentCollectionItem]!\n @relationFrom(model: "ContentCollectionItem", property: "collectionID")\n}\n'})}),"\n",(0,o.jsxs)(n.admonition,{title:"Circular references",type:"caution",children:[(0,o.jsxs)(n.p,{children:["ComposeDB does not support creating relations with circular references, such as ",(0,o.jsx)(n.code,{children:"ContentCollection"})," -> ",(0,o.jsx)(n.code,{children:"ContentCollectionItem"})," -> ",(0,o.jsx)(n.code,{children:"ContentCollection"})," in the example above."]}),(0,o.jsxs)(n.p,{children:["To work around this limitation, it is possible to use the ",(0,o.jsx)(n.code,{children:"Node"})," interface as a placeholder for any model. The example above uses the ",(0,o.jsx)(n.code,{children:"Node"})," interface instead of ",(0,o.jsx)(n.code,{children:"ContentCollection"})," to reference the collection in the ",(0,o.jsx)(n.code,{children:"ContentCollectionItem"})," in order to avoid creating a circular reference."]})]}),"\n",(0,o.jsx)(n.h2,{id:"account-to-account",children:"Account to Account"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsx)(n.p,{children:"Account to account relations are on the roadmap, but not yet supported."})}),"\n",(0,o.jsx)(n.p,{children:"Account to account relations enable you to define a relationship between an account and a different account, and query both ways based on that relationship. This is useful for creating structures such as social graphs where the relationship represents a follow."}),"\n",(0,o.jsx)(n.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Now that you understand the fundamentals of creating models with different types of relations, let's create a ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/data-modeling/composites",children:(0,o.jsx)(n.strong,{children:"composite"})})," so we can use it in our app."]})]})}function m(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},63883:(e,n,t)=>{t.d(n,{Z:()=>c,a:()=>l});var o=t(50959);const i={},s=o.createContext(i);function l(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5180],{13146:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>r,contentTitle:()=>l,default:()=>m,frontMatter:()=>s,metadata:()=>c,toc:()=>a});var o=t(11527),i=t(63883);const s={},l="Relations",c={id:"composedb/guides/data-modeling/relations",title:"Relations",description:"Define queryable relationships between models and other models or accounts.",source:"@site/docs/composedb/guides/data-modeling/relations.mdx",sourceDirName:"composedb/guides/data-modeling",slug:"/composedb/guides/data-modeling/relations",permalink:"/docs/composedb/guides/data-modeling/relations",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Schemas",permalink:"/docs/composedb/guides/data-modeling/schemas"},next:{title:"Composites",permalink:"/docs/composedb/guides/data-modeling/composites"}},r={},a=[{value:"Types of Relations",id:"types-of-relations",level:2},{value:"Account to Model",id:"account-to-model",level:2},{value:"Example: Simple Profile",id:"example-simple-profile",level:3},{value:"Model to Account",id:"model-to-account",level:2},{value:"Example: Direct message (DM)",id:"example-direct-message-dm",level:3},{value:"Model to Model",id:"model-to-model",level:2},{value:"Example: Post with comments and likes",id:"example-post-with-comments-and-likes",level:3},{value:"Using interfaces",id:"using-interfaces",level:3},{value:"Account to Account",id:"account-to-account",level:2},{value:"Next Steps",id:"next-steps",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"relations",children:"Relations"}),"\n",(0,o.jsx)(n.p,{children:"Define queryable relationships between models and other models or accounts."}),"\n",(0,o.jsx)(n.h2,{id:"types-of-relations",children:"Types of Relations"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.p,{children:"There are a few primary forms of relations currently supported by ComposeDB:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#account-to-model",children:"Account to model relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#model-to-account",children:"Model to account relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#model-to-model",children:"Model to model relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#account-to-account",children:"Account to account relations"})}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"account-to-model",children:"Account to Model"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Account to model relations enable linking and querying data to the account that created it. By default the ",(0,o.jsx)(n.code,{children:"@createmodel"})," directive (used when creating a new model) requires that every model must specify a relation to its author\u2019s account. This was covered in ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"}),"."]}),"\n",(0,o.jsx)(n.h3,{id:"example-simple-profile",children:"Example: Simple Profile"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model for a very simple user profile that can be queried based on the author:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Define simple profile model\n# Relate it to the author\'s account\n# Limit to one profile per account\n# Enable queries based on author\n\ntype SimpleProfile @createModel(accountRelation: SINGLE, description: "Very basic profile") {\n displayName: String! @string(minLength: 3, maxLength: 50)\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"accountRelation"})," relates the profile to the author\u2019s account"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"SINGLE"})," limits to one profile per account"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"model-to-account",children:"Model to Account"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Model to account relations enable you to link data to and query data from an account other than the data\u2019s author. When using this type of relation, you need to define a model field that stores an account (e.g. a ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/composedb-client/user-sessions",children:"DID"}),"), then add the ",(0,o.jsx)(n.code,{children:"@accountReference"})," directive to make it queryable."]}),"\n",(0,o.jsx)(n.h3,{id:"example-direct-message-dm",children:"Example: Direct message (DM)"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model for a user-to-user message that can be queried based on the recipient:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:"# Define message model\n# Relate it to author's account\n# Allow unlimited sent messages\n# Store reference to recipient's account\n# Enable queries based on recipient\n\ntype Message @createModel(accountRelation: LIST, description: \"Direct message model\") {\n recipient: DID! @accountReference\n directMessage: String! @string(minLength: 1, maxLength: 200)\n}\n"})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"accountRelation"})," relates the message to the author\u2019s account"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"LIST"})," allows unlimited messages"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"recipient"})," references the recipient\u2019s account by storing its ",(0,o.jsx)(n.code,{children:"DID!"}),", using ",(0,o.jsx)(n.code,{children:"@accountReference"})]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"model-to-model",children:"Model to Model"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.p,{children:"Model to model relations enable you to link data to and query data from another piece of data. These relations can be uni-directional (e.g. query a post from a comment) or bi-directional (e.g. query a post from a comment and query all comments from a post)."}),"\n",(0,o.jsxs)(n.p,{children:["There is type of model-to-model relation that includes the user as part of the relationship. This is achieved by using the ",(0,o.jsx)(n.code,{children:"SET"})," account relation type, which allows users to enforce a constraint where each user account (or DID) can create only one instance of a model for a specific record of another model."]}),"\n",(0,o.jsx)(n.h3,{id:"example-post-with-comments-and-likes",children:"Example: Post with comments and likes"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model that allows many comments from the same or different account to be made on a single post. It supports unlimited comments per user, and bi-directional queries from any comment or like to the original post and from the original post to all of its comments and likes. The model schema also creates a relation between posts and likes enabling a single like per post by an account, meaning a single account will only be able to like the post once"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Load post model (using streamID)\n\ntype Post @loadModel(id: "kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy") {\n id: ID!\n}\n\n# New comment model\n# Set reference to original post\n# Enable querying comment to get original post\n\ntype Comment @createModel(accountRelation: LIST, description: "A comment on a Post") {\n postID: StreamID! @documentReference(model: "Post")\n post: Post! @relationDocument(property: "postID")\n text: String! @string(maxLength: 500)\n}\n\n# New like model\n# Set relationship to original post\n# Enable querying comment to get original post\ntype Like @createModel(description: "A like on a post", accountRelation: SET, accountRelationFields: ["postID"]) {\n postID: StreamID! @documentReference(model: "Post")\n post: Post! @relationDocument(property: "postID")\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Relations can also be created between models loaded from known streamIDs"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Load comment model\n\ntype Comment @loadModel(id: "kjzl6hvfrbw6c9oo2ync09y6z5c9mas9u49lfzcowepuzxmcn3pzztvzd0c7gh0") {\n id: ID!\n}\n\n# Load post model\n# Extend post model with comments and likes\n# Set relationships to all comments and likes\n# Enable querying post to get all comments and likes\n\ntype Post @loadModel(id: "kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy") {\n comments: [Comment] @relationFrom(model: "Comment", property: "postID")\n likes: [Like] @relationFrom(model: "Like", property: "postID")\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"id"})," is a simple placeholder, since empty types are not allowed"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"postID"})," defines the relationship from a comment to the original post, using ",(0,o.jsx)(n.code,{children:"@documentReference"})]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"post"})," allows accessing the original post from the comment, using ",(0,o.jsx)(n.code,{children:"@relationDocument"})]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"text"})," defines a string for the comment"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"comments"})," defines the relationships from a post to a collection of comments, using ",(0,o.jsx)(n.code,{children:"@relationFrom"}),"; requires specifying the model relation (",(0,o.jsx)(n.code,{children:"Comment"}),") and the specific property that stores the relation (",(0,o.jsx)(n.code,{children:"postID"}),")"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"likes"})," defines the relationships from a post to a collection of comments, using ",(0,o.jsx)(n.code,{children:"@relationFrom"}),"; requires specifying the model relation (",(0,o.jsx)(n.code,{children:"Like"}),") and the specific property that stores the relation (",(0,o.jsx)(n.code,{children:"postID"}),")"]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"using-interfaces",children:"Using interfaces"}),"\n",(0,o.jsx)(n.p,{children:"When defining relations, it is possible to reference model interfaces to allow for a wider range of documents in the relations set, for example to create a collection of documents using different models implementing the same interface:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'interface TextContent @createModel(description: "Required text content interface") {\n text: String! @string(maxLength: 10000)\n}\n\ntype Page implements TextContent @createModel(description: "Page model") {\n title: String @string(maxLength: 100)\n text: String! @string(maxLength: 10000)\n}\n\ntype Post implements TextContent @createModel(description: "Post model") {\n title: String! @string(maxLength: 100)\n text: String! @string(maxLength: 10000)\n createdAt: DateTime!\n}\n\ntype ContentCollectionItem\n @createModel(description: "Association between a collection and an item") {\n # The Node interface is used here instead of ContentCollection, see warning below\n collectionID: StreamID! @documentReference(model: "Node")\n collection: Node! @relationDocument(property: "collectionID")\n itemID: StreamID! @documentReference(model: "TextContent")\n item: TextContent! @relationDocument(property: "itemID")\n}\n\ntype ContentCollection @createModel(description: "Collection of text contents") {\n name: String @string(maxLength: 50)\n items: [ContentCollectionItem]!\n @relationFrom(model: "ContentCollectionItem", property: "collectionID")\n}\n'})}),"\n",(0,o.jsxs)(n.admonition,{title:"Circular references",type:"caution",children:[(0,o.jsxs)(n.p,{children:["ComposeDB does not support creating relations with circular references, such as ",(0,o.jsx)(n.code,{children:"ContentCollection"})," -> ",(0,o.jsx)(n.code,{children:"ContentCollectionItem"})," -> ",(0,o.jsx)(n.code,{children:"ContentCollection"})," in the example above."]}),(0,o.jsxs)(n.p,{children:["To work around this limitation, it is possible to use the ",(0,o.jsx)(n.code,{children:"Node"})," interface as a placeholder for any model. The example above uses the ",(0,o.jsx)(n.code,{children:"Node"})," interface instead of ",(0,o.jsx)(n.code,{children:"ContentCollection"})," to reference the collection in the ",(0,o.jsx)(n.code,{children:"ContentCollectionItem"})," in order to avoid creating a circular reference."]})]}),"\n",(0,o.jsx)(n.h2,{id:"account-to-account",children:"Account to Account"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsx)(n.p,{children:"Account to account relations are on the roadmap, but not yet supported."})}),"\n",(0,o.jsx)(n.p,{children:"Account to account relations enable you to define a relationship between an account and a different account, and query both ways based on that relationship. This is useful for creating structures such as social graphs where the relationship represents a follow."}),"\n",(0,o.jsx)(n.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Now that you understand the fundamentals of creating models with different types of relations, let's create a ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/data-modeling/composites",children:(0,o.jsx)(n.strong,{children:"composite"})})," so we can use it in our app."]})]})}function m(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},63883:(e,n,t)=>{t.d(n,{Z:()=>c,a:()=>l});var o=t(50959);const i={},s=o.createContext(i);function l(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9501b78f.4ee046de.js b/assets/js/9501b78f.4ee046de.js deleted file mode 100644 index 67ccf1a0..00000000 --- a/assets/js/9501b78f.4ee046de.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4533],{41608:(e,o,s)=>{s.r(o),s.d(o,{assets:()=>d,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>m});var n=s(11527),t=s(63883),i=s(37421),r=s(81779);const a={},c="Composites",l={id:"composedb/guides/data-modeling/composites",title:"Composites",description:"Guides for creating, deploying, and using composites.",source:"@site/docs/composedb/guides/data-modeling/composites.mdx",sourceDirName:"composedb/guides/data-modeling",slug:"/composedb/guides/data-modeling/composites",permalink:"/docs/composedb/guides/data-modeling/composites",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Relations",permalink:"/docs/composedb/guides/data-modeling/relations"},next:{title:"ComposeDB Client",permalink:"/docs/composedb/guides/composedb-client/"}},d={},m=[{value:"Overview",id:"overview",level:2},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Basic Usage",id:"basic-usage",level:2},{value:"Creating composites",id:"creating-composites",level:3},{value:"Deploying composites",id:"deploying-composites",level:3},{value:"Compiling composites",id:"compiling-composites",level:3},{value:"Advanced",id:"advanced",level:2},{value:"Merging composites",id:"merging-composites",level:3},{value:"Extracting composites",id:"extracting-composites",level:3},{value:"Inspecting composites",id:"inspecting-composites",level:3},{value:"Aliasing composites",id:"aliasing-composites",level:3},{value:"Next Steps",id:"next-steps",level:2},{value:"Related Guides",id:"related-guides",level:2}];function p(e){const o={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(o.h1,{id:"composites",children:"Composites"}),"\n",(0,n.jsx)(o.p,{children:"Guides for creating, deploying, and using composites."}),"\n",(0,n.jsx)(o.h2,{id:"overview",children:"Overview"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsx)(o.p,{children:"In order to start using a model in your app, you\u2019ll have to include it in a composite. Composites are collections of one or more models and represent the complete GraphQL schema for your app. For basic usage, follow these steps:"}),"\n",(0,n.jsxs)(o.ol,{children:["\n",(0,n.jsx)(o.li,{children:"Create a composite containing one or more models"}),"\n",(0,n.jsx)(o.li,{children:"Deploy the composite to your ComposeDB server"}),"\n",(0,n.jsx)(o.li,{children:"Compile the composite for usage by your ComposeDB client"}),"\n"]}),"\n",(0,n.jsx)(o.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsxs)(o.ul,{children:["\n",(0,n.jsx)(o.li,{children:"If you want to manage your composites from the CLI, you will need to have it installed"}),"\n",(0,n.jsxs)(o.li,{children:["If you want to manage your composites from JavaScript, you will need to install the\xa0",(0,n.jsx)(o.a,{href:"https://composedb.js.org/docs/0.5.x/api/modules/devtools",children:(0,n.jsx)(o.code,{children:"@composedb/devtools"})}),"\xa0library"]}),"\n",(0,n.jsxs)(o.li,{children:["One or more ",(0,n.jsx)(o.code,{children:".graphql"})," files containing your models"]}),"\n"]}),"\n",(0,n.jsx)(o.h2,{id:"basic-usage",children:"Basic Usage"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsx)(o.h3,{id:"creating-composites",children:"Creating composites"}),"\n",(0,n.jsxs)(o.p,{children:["Let\u2019s say you have a model written in a ",(0,n.jsx)(o.code,{children:"my-schema.graphql"})," file. To convert this schema into a composite, run the following:"]}),"\n",(0,n.jsxs)(i.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,n.jsx)(r.Z,{value:"cli",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:create my-schema.graphql --output=my-composite.json --did-private-key=your-private-key\n"})})}),(0,n.jsx)(r.Z,{value:"js",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { DID } from 'dids'\nimport { Ed25519Provider } from 'key-did-provider-ed25519'\nimport { getResolver } from 'key-did-resolver'\nimport { fromString } from 'uint8arrays/from-string'\n\n// Import the devtool node package\nimport { createComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\n// Hexadecimal-encoded private key for a DID having admin access to the target Ceramic node\n// Replace the example key here by your admin private key\nconst privateKey = fromString('b0cb[...]515f', 'base16')\n\nconst did = new DID({\n resolver: getResolver(),\n provider: new Ed25519Provider(privateKey),\n})\nawait did.authenticate()\n\n// Replace by the URL of the Ceramic node you want to deploy the Models to\nconst ceramic = new CeramicClient('http://localhost:7007')\n// An authenticated DID with admin access must be set on the Ceramic instance\nceramic.did = did\n\n// Replace by the path to the source schema file\nconst composite = await createComposite(ceramic, './source-schema.graphql')\n\n// Replace by the path to the encoded composite file\nawait writeEncodedComposite(composite, './my-composite.json')\n"})})})]}),"\n",(0,n.jsxs)(o.p,{children:["This will create a file called ",(0,n.jsx)(o.code,{children:"my-composite.json"})," which contains the composite in JSON."]}),"\n",(0,n.jsx)(o.h3,{id:"deploying-composites",children:"Deploying composites"}),"\n",(0,n.jsx)(o.p,{children:"After creating the composite, deploy it to your local node:"}),"\n",(0,n.jsxs)(i.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,n.jsx)(r.Z,{value:"cli",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:deploy my-composite.json --ceramic-url=http://localhost:7007 --did-private-key=your-private-key\n"})})}),(0,n.jsx)(r.Z,{value:"js",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { DID } from 'dids'\nimport { Ed25519Provider } from 'key-did-provider-ed25519'\nimport { getResolver } from 'key-did-resolver'\nimport { fromString } from 'uint8arrays/from-string'\n\nimport { readEncodedComposite } from '@composedb/devtools-node'\n\n// Hexadecimal-encoded private key for a DID having admin access to the target Ceramic node\n// Replace the example key here by your admin private key\nconst privateKey = fromString('b0cb[...]515f', 'base16')\n\nconst did = new DID({\n resolver: getResolver(),\n provider: new Ed25519Provider(privateKey),\n})\nawait did.authenticate()\n\n// Replace by the URL of the Ceramic node you want to deploy the Models to\nconst ceramic = new CeramicClient('http://localhost:7007')\n// An authenticated DID with admin access must be set on the Ceramic instance\nceramic.did = did\n\n// Replace by the path to the local encoded composite file\nconst composite = await readEncodedComposite(ceramic, 'my-first-composite.json')\n\n// Notify the Ceramic node to index the models present in the composite\nawait composite.startIndexingOn(ceramic)\n"})})})]}),"\n",(0,n.jsx)(o.admonition,{type:"tip",children:(0,n.jsxs)(o.p,{children:["This will also automatically add all models contained in the composite to the ",(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"}),"."]})}),"\n",(0,n.jsx)(o.h3,{id:"compiling-composites",children:"Compiling composites"}),"\n",(0,n.jsxs)(o.p,{children:["After deploying your composite, compile it so you can start perform ",(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-interactions/",children:"data interactions"})," using the ComposeDB client."]}),"\n",(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:compile my-first-composite.json runtime-composite.json\n"})}),"\n",(0,n.jsx)(o.h2,{id:"advanced",children:"Advanced"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsx)(o.h3,{id:"merging-composites",children:"Merging composites"}),"\n",(0,n.jsx)(o.p,{children:"If you have more than one composite, you need to merge them into a single composite for use in your app. This may apply when:"}),"\n",(0,n.jsxs)(o.ul,{children:["\n",(0,n.jsxs)(o.li,{children:["You want to use multiple models from the ",(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog#using-multiple-models",children:"catalog"})]}),"\n",(0,n.jsx)(o.li,{children:"You want to use a model from the catalog and one or more models you created"}),"\n",(0,n.jsx)(o.li,{children:"You create multiple models and store their schemas in different GraphQL files"}),"\n"]}),"\n",(0,n.jsxs)(o.p,{children:["Let\u2019s say you have two composites where ",(0,n.jsx)(o.code,{children:"simple-profile-composite.json"})," contains the model for a profile model and ",(0,n.jsx)(o.code,{children:"post-composite.json"})," contains the model for a post. To merge, reference both composite JSON files and specify an output file path for the merged composite."]}),"\n",(0,n.jsxs)(i.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,n.jsx)(r.Z,{value:"cli",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:merge simple-profile-composite.json post-composite.json --output=merged-composite.json\n"})})}),(0,n.jsxs)(r.Z,{value:"js",children:[(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { Composite } from '@composedb/devtools'\nimport { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\nconst ceramic = new CeramicClient('http://localhost:7007')\n\nconst loadSources = [\n 'simple-profile-composite.json',\n 'post-composite.json',\n].map(async (path) => await readEncodedComposite(ceramic, path))\nconst sourceComposites = await Promise.all(loadSources)\nconst mergedComposite = Composite.from(sourceComposites)\n\nawait writeEncodedComposite(mergedComposite, 'merged-composite.json')\n"})}),(0,n.jsxs)(o.admonition,{type:"caution",children:[(0,n.jsxs)(o.p,{children:[(0,n.jsx)(o.em,{children:(0,n.jsx)(o.strong,{children:"Note:"})})," To run the code above, you need a Ceramic JS HTTP client library installed on your machine to connect your app to a Ceramic node. Ceramic JS HTTP client can be installed by running the following command:"]}),(0,n.jsx)(o.p,{children:(0,n.jsx)(o.code,{children:"pnpm install @ceramicnetwork/http-client"})})]})]})]}),"\n",(0,n.jsxs)(o.p,{children:["The output of either example is a new file named ",(0,n.jsx)(o.code,{children:"merged-composite.json"})," which contains the models of both merged composites. From here you need to ",(0,n.jsx)(o.a,{href:"#deploying-composites",children:"deploy"})," the composite to your node, then ",(0,n.jsx)(o.a,{href:"#compiling-composites",children:"compile"})," the composite to start using it."]}),"\n",(0,n.jsx)(o.h3,{id:"extracting-composites",children:"Extracting composites"}),"\n",(0,n.jsx)(o.p,{children:"In cases where your composite contain models not needed by your application, or in other cases where you generally want to separate models in your composite, you can extract models into a separate composite."}),"\n",(0,n.jsxs)(o.p,{children:["As an example, let\u2019s reuse the ",(0,n.jsx)(o.code,{children:"merged-composite.json"})," file from the previous section and assume you want to extract the profile model into a separate composite. To do this, load the ",(0,n.jsx)(o.code,{children:"merged-composite.json"})," file and specify which model(s) you\u2019d like to extract into a new composite file."]}),"\n",(0,n.jsxs)(i.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,n.jsx)(r.Z,{value:"cli",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:extract-model merged-composite.json kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc --output=new-composite.json\n"})})}),(0,n.jsx)(r.Z,{value:"js",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { Composite } from '@composedb/devtools'\nimport { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\nconst ceramic = new CeramicClient('http://localhost:7007')\nconst sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')\n\nconst mergedComposite = sourceComposite.copy(['kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc'])\nawait writeEncodedComposite(mergedComposite, 'new-composite.json')\n"})})})]}),"\n",(0,n.jsxs)(o.p,{children:["This will create a file called ",(0,n.jsx)(o.code,{children:"new-composite.json"})," with your profile model in it. From here you need to deploy the composite to your node, then ",(0,n.jsx)(o.a,{href:"#compiling-composites",children:"compile"})," the composite to start using it."]}),"\n",(0,n.jsx)(o.h3,{id:"inspecting-composites",children:"Inspecting composites"}),"\n",(0,n.jsx)(o.p,{children:"If you want to check what models are included in a specific composite, follow the steps below:"}),"\n",(0,n.jsxs)(o.ol,{children:["\n",(0,n.jsxs)(o.li,{children:["\n",(0,n.jsxs)(o.p,{children:["Compile the composite:\n",(0,n.jsx)(o.code,{children:"composedb composite:compile my-first-composite.json runtime-composite.json"})]}),"\n"]}),"\n",(0,n.jsxs)(o.li,{children:["\n",(0,n.jsxs)(o.p,{children:["View the GraphQL schema of the composite:\n",(0,n.jsx)(o.a,{href:"https://composedb.js.org/docs/0.5.x/api/commands/cli.graphql",children:(0,n.jsx)(o.code,{children:"composedb graphql:schema runtime-composite.json --output=schema.graphql"})})]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(o.h3,{id:"aliasing-composites",children:"Aliasing composites"}),"\n",(0,n.jsx)(o.p,{children:"In general, models are referenced using their unique model streamIDs which are not memorable. Models can be more easily referenced by aliasing them to your preferred names."}),"\n",(0,n.jsxs)(o.p,{children:["To manually set aliases for your models, add the following section to your composite JSON file. In this case we will use the aliases ",(0,n.jsx)(o.code,{children:"SimpleProfile"})," and ",(0,n.jsx)(o.code,{children:"Post"}),"."]}),"\n",(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:'"aliases":{\n "kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc":"SimpleProfile",\n "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96":"Post"\n }\n'})}),"\n",(0,n.jsxs)(o.p,{children:["To do aliases programmatically, use the ComposeDB Devtools library. Here\u2019s an example script that loads a composite JSON file and assigns ",(0,n.jsx)(o.code,{children:"SimpleProfile"})," and ",(0,n.jsx)(o.code,{children:"Post"}),":"]}),"\n",(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { Composite } from '@composedb/devtools'\nimport { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\nconst ceramic = new CeramicClient('http://localhost:7007')\nconst sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')\n\nconst newComposite = sourceComposite.setAliases({\n 'kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc': 'SimpleProfile',\n 'kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96': 'Post',\n})\nawait writeEncodedComposite(newComposite, 'new-composite.json')\n"})}),"\n",(0,n.jsxs)(o.p,{children:["This script will create a file named ",(0,n.jsx)(o.code,{children:"new-composite.json"})," including model aliases:"]}),"\n",(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:'"aliases":{\n "kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc":"SimpleProfile",\n "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96":"Post"\n }\n'})}),"\n",(0,n.jsxs)(o.p,{children:["From here you need to ",(0,n.jsx)(o.a,{href:"#deploying-composites",children:"deploy"})," the composite to your node, then ",(0,n.jsx)(o.a,{href:"#compiling-composites",children:"compile"})," the composite to start using it. When interacting with the models inside your app, you can refer to them using their human-readable aliases rather than their streamIDs."]}),"\n",(0,n.jsx)(o.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsxs)(o.p,{children:["Set up your ",(0,n.jsx)(o.a,{href:"/docs/composedb/guides/composedb-client/",children:(0,n.jsx)(o.strong,{children:"ComposeDB Client"})})]}),"\n",(0,n.jsx)(o.h2,{id:"related-guides",children:"Related Guides"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsxs)(o.ul,{children:["\n",(0,n.jsx)(o.li,{children:(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"})}),"\n",(0,n.jsx)(o.li,{children:(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"})}),"\n"]})]})}function u(e={}){const{wrapper:o}={...(0,t.a)(),...e.components};return o?(0,n.jsx)(o,{...e,children:(0,n.jsx)(p,{...e})}):p(e)}},81779:(e,o,s)=>{s.d(o,{Z:()=>r});s(50959);var n=s(45924);const t={tabItem:"tabItem_e7Wc"};var i=s(11527);function r(e){let{children:o,hidden:s,className:r}=e;return(0,i.jsx)("div",{role:"tabpanel",className:(0,n.Z)(t.tabItem,r),hidden:s,children:o})}},37421:(e,o,s)=>{s.d(o,{Z:()=>w});var n=s(50959),t=s(45924),i=s(71988),r=s(28903),a=s(739),c=s(99965),l=s(43251),d=s(76698);function m(e){return n.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,n.isValidElement)(e)&&function(e){const{props:o}=e;return!!o&&"object"==typeof o&&"value"in o}(e))return e;throw new Error(`Docusaurus error: BadIn this section we will show how to create a composite by downloading models from the model catalog.
You can fetch any existing model from the catalog by referencing the model’s unique ID. For example, for your basic social media app, use the existing model SimpleProfile
. To fetch the model, to your working directory, take note of the model stream ID in the table above and run the following command:
composedb composite:from-model kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep --ceramic-url=http://localhost:7007 --output=my-first-composite.json
composedb composite:from-model kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65 --ceramic-url=http://localhost:7007 --output=my-first-composite.json
You should see the following output in your terminal:
✔ Creating a composite from models... Composite was created and its encoded representation was saved in my-first-composite.json
This output means that you now have the SimpleProfile
model stored locally in a file called my-first-composite.json
.
If your application needs multiple models, for example the SimpleProfile
and Post
models, you can. To fetch them, take note of the model stream IDs and provide them in a ComposeDB CLI command as follows:
composedb composite:from-model kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep kjzl6hvfrbw6c7gkodzmqq5s031yfo5xdllvcr1z0tumwl7kpml4gfe5gbwh2bg --ceramic-url=http://localhost:7007 --output=my-first-composite.json
composedb composite:from-model kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65 kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy --ceramic-url=http://localhost:7007 --output=my-first-composite.json
The output of this command will be a composite file named my-first-composite.json
.
You will have to deploy the composite with fetched models to your local Ceramic node so that they can be used when building and running your applications. This can be achieved by using ComposeDB CLI and referencing the composite file of fetched models in your local environment as shown below. Note that you have to provide your did private key to deploy the model:
composedb composite:deploy my-first-composite.json --ceramic-url=http://localhost:7007 --did-private-key=your-private-key
You should see the output similar to the one below:
-ℹ Using DID did:key:z6MkoDgemAx51v8w692aZRLPdwP6UPKj3EgUhBTvbL7hCwLu
✔ Deploying the composite... Done!
["kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep"]
ℹ Using DID did:key:z6MkoDgemAx51v8w692aZRLPdwP6UPKj3EgUhBTvbL7hCwLu
✔ Deploying the composite... Done!
["kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65"]
Whenever composites are deployed, the models will be automatically indexed. This also means that these models are shared across the network (at the moment, only Clay testnet). If you check the output produced by the terminal that runs your Ceramic local node, you should see a similar output:
-IMPORTANT: Starting indexing for Model kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep
IMPORTANT: Starting indexing for Model kjzl6hvfrbw6c7gkodzmqq5s031yfo5xdllvcr1z0tumwl7kpml4gfe5gbwh2bg
IMPORTANT: Creating ComposeDB Indexing table for model: kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep
IMPORTANT: Creating ComposeDB Indexing table for model: kjzl6hvfrbw6c7gkodzmqq5s031yfo5xdllvcr1z0tumwl7kpml4gfe5gbwh2bg
IMPORTANT: Starting indexing for Model kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65
IMPORTANT: Starting indexing for Model kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy
IMPORTANT: Creating ComposeDB Indexing table for model: kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65
IMPORTANT: Creating ComposeDB Indexing table for model: kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy
This means that the composite was deployed and the models were indexed on your local node successfully! 🎉
The last step left is compiling the composite. This is necessary to interact with the data in the next step of this guide:
diff --git a/docs/composedb/examples.html b/docs/composedb/examples.html index 61fcc8a9..e337bab3 100644 --- a/docs/composedb/examples.html +++ b/docs/composedb/examples.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/examples/tutorials-and-examples.html b/docs/composedb/examples/tutorials-and-examples.html index 92b49c27..bf396e44 100644 --- a/docs/composedb/examples/tutorials-and-examples.html +++ b/docs/composedb/examples/tutorials-and-examples.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/examples/verifiable-credentials.html b/docs/composedb/examples/verifiable-credentials.html index 0b4c4d92..8f4a7396 100644 --- a/docs/composedb/examples/verifiable-credentials.html +++ b/docs/composedb/examples/verifiable-credentials.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/getting-started.html b/docs/composedb/getting-started.html index 0771ed1f..f5a1ab67 100644 --- a/docs/composedb/getting-started.html +++ b/docs/composedb/getting-started.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides.html b/docs/composedb/guides.html index fbc2a099..32c0edd7 100644 --- a/docs/composedb/guides.html +++ b/docs/composedb/guides.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-client.html b/docs/composedb/guides/composedb-client.html index ba9859dc..b678cdec 100644 --- a/docs/composedb/guides/composedb-client.html +++ b/docs/composedb/guides/composedb-client.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-client/authenticate-users.html b/docs/composedb/guides/composedb-client/authenticate-users.html index 64fbf2cd..1a7977aa 100644 --- a/docs/composedb/guides/composedb-client/authenticate-users.html +++ b/docs/composedb/guides/composedb-client/authenticate-users.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-client/javascript-client.html b/docs/composedb/guides/composedb-client/javascript-client.html index f2c8f8e5..03c711e9 100644 --- a/docs/composedb/guides/composedb-client/javascript-client.html +++ b/docs/composedb/guides/composedb-client/javascript-client.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-client/user-sessions.html b/docs/composedb/guides/composedb-client/user-sessions.html index 9e66ca45..ba6fb378 100644 --- a/docs/composedb/guides/composedb-client/user-sessions.html +++ b/docs/composedb/guides/composedb-client/user-sessions.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-client/using-apollo.html b/docs/composedb/guides/composedb-client/using-apollo.html index 27ac7c54..14e5156f 100644 --- a/docs/composedb/guides/composedb-client/using-apollo.html +++ b/docs/composedb/guides/composedb-client/using-apollo.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-client/using-relay.html b/docs/composedb/guides/composedb-client/using-relay.html index 10c6ddd9..1c8cd6f5 100644 --- a/docs/composedb/guides/composedb-client/using-relay.html +++ b/docs/composedb/guides/composedb-client/using-relay.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-server.html b/docs/composedb/guides/composedb-server.html index ce0248e7..beaf7595 100644 --- a/docs/composedb/guides/composedb-server.html +++ b/docs/composedb/guides/composedb-server.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-server/access-mainnet.html b/docs/composedb/guides/composedb-server/access-mainnet.html index a42cf2f3..6cc54ef4 100644 --- a/docs/composedb/guides/composedb-server/access-mainnet.html +++ b/docs/composedb/guides/composedb-server/access-mainnet.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-server/data-storage.html b/docs/composedb/guides/composedb-server/data-storage.html index e5db7ed4..e1a2da0a 100644 --- a/docs/composedb/guides/composedb-server/data-storage.html +++ b/docs/composedb/guides/composedb-server/data-storage.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-server/running-in-the-cloud.html b/docs/composedb/guides/composedb-server/running-in-the-cloud.html index ccf25b89..f615f706 100644 --- a/docs/composedb/guides/composedb-server/running-in-the-cloud.html +++ b/docs/composedb/guides/composedb-server/running-in-the-cloud.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-server/running-locally.html b/docs/composedb/guides/composedb-server/running-locally.html index 72c9bb9b..b43b0f33 100644 --- a/docs/composedb/guides/composedb-server/running-locally.html +++ b/docs/composedb/guides/composedb-server/running-locally.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/composedb-server/server-configurations.html b/docs/composedb/guides/composedb-server/server-configurations.html index c34a90e3..de06623b 100644 --- a/docs/composedb/guides/composedb-server/server-configurations.html +++ b/docs/composedb/guides/composedb-server/server-configurations.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/data-interactions.html b/docs/composedb/guides/data-interactions.html index 6d651ef7..90df5c20 100644 --- a/docs/composedb/guides/data-interactions.html +++ b/docs/composedb/guides/data-interactions.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/data-interactions/mutations.html b/docs/composedb/guides/data-interactions/mutations.html index 1a1eb49d..cfe6e2eb 100644 --- a/docs/composedb/guides/data-interactions/mutations.html +++ b/docs/composedb/guides/data-interactions/mutations.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/data-interactions/queries.html b/docs/composedb/guides/data-interactions/queries.html index a1e329b1..de764f80 100644 --- a/docs/composedb/guides/data-interactions/queries.html +++ b/docs/composedb/guides/data-interactions/queries.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/data-modeling.html b/docs/composedb/guides/data-modeling.html index b407c6ce..2976e8a2 100644 --- a/docs/composedb/guides/data-modeling.html +++ b/docs/composedb/guides/data-modeling.html @@ -13,7 +13,7 @@ - + diff --git a/docs/composedb/guides/data-modeling/composites.html b/docs/composedb/guides/data-modeling/composites.html index 389f0bd7..3df1e7b4 100644 --- a/docs/composedb/guides/data-modeling/composites.html +++ b/docs/composedb/guides/data-modeling/composites.html @@ -13,7 +13,7 @@ - + @@ -64,7 +64,7 @@In cases where your composite contain models not needed by your application, or in other cases where you generally want to separate models in your composite, you can extract models into a separate composite.
As an example, let’s reuse the merged-composite.json
file from the previous section and assume you want to extract the profile model into a separate composite. To do this, load the merged-composite.json
file and specify which model(s) you’d like to extract into a new composite file.
composedb composite:extract-model merged-composite.json kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc --output=new-composite.json
import { CeramicClient } from '@ceramicnetwork/http-client'
import { Composite } from '@composedb/devtools'
import { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'
const ceramic = new CeramicClient('http://localhost:7007')
const sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')
const mergedComposite = sourceComposite.copy(['kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc'])
await writeEncodedComposite(mergedComposite, 'new-composite.json')
composedb composite:extract-model merged-composite.json kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65 --output=new-composite.json
import { CeramicClient } from '@ceramicnetwork/http-client'
import { Composite } from '@composedb/devtools'
import { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'
const ceramic = new CeramicClient('http://localhost:7007')
const sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')
const mergedComposite = sourceComposite.copy(['kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65'])
await writeEncodedComposite(mergedComposite, 'new-composite.json')
This will create a file called new-composite.json
with your profile model in it. From here you need to deploy the composite to your node, then compile the composite to start using it.
If you want to check what models are included in a specific composite, follow the steps below:
@@ -81,11 +81,11 @@In general, models are referenced using their unique model streamIDs which are not memorable. Models can be more easily referenced by aliasing them to your preferred names.
To manually set aliases for your models, add the following section to your composite JSON file. In this case we will use the aliases SimpleProfile
and Post
.
"aliases":{
"kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc":"SimpleProfile",
"kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96":"Post"
}
"aliases":{
"kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65":"SimpleProfile",
"kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy":"Post"
}
To do aliases programmatically, use the ComposeDB Devtools library. Here’s an example script that loads a composite JSON file and assigns SimpleProfile
and Post
:
import { CeramicClient } from '@ceramicnetwork/http-client'
import { Composite } from '@composedb/devtools'
import { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'
const ceramic = new CeramicClient('http://localhost:7007')
const sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')
const newComposite = sourceComposite.setAliases({
'kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc': 'SimpleProfile',
'kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96': 'Post',
})
await writeEncodedComposite(newComposite, 'new-composite.json')
import { CeramicClient } from '@ceramicnetwork/http-client'
import { Composite } from '@composedb/devtools'
import { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'
const ceramic = new CeramicClient('http://localhost:7007')
const sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')
const newComposite = sourceComposite.setAliases({
'kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65': 'SimpleProfile',
'kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy': 'Post',
})
await writeEncodedComposite(newComposite, 'new-composite.json')
This script will create a file named new-composite.json
including model aliases:
"aliases":{
"kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc":"SimpleProfile",
"kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96":"Post"
}
"aliases":{
"kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65":"SimpleProfile",
"kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy":"Post"
}
From here you need to deploy the composite to your node, then compile the composite to start using it. When interacting with the models inside your app, you can refer to them using their human-readable aliases rather than their streamIDs.
Fetch a single model from the catalog and convert it into a composite, using its model ID:
-composedb composite:from-model kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc --output=my-composite.json
composedb composite:from-model kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65 --output=my-composite.json
Run the composite:from-model
command depicted above for each model you want to use in your application. Remember to change the composite file name to avoid collisions. After you have multiple composite files, merge them. See Merging Composites.
There is type of model-to-model relation that includes the user as part of the relationship. This is achieved by using the SET
account relation type, which allows users to enforce a constraint where each user account (or DID) can create only one instance of a model for a specific record of another model.
Here’s a model that allows many comments from the same or different account to be made on a single post. It supports unlimited comments per user, and bi-directional queries from any comment or like to the original post and from the original post to all of its comments and likes. The model schema also creates a relation between posts and likes enabling a single like per post by an account, meaning a single account will only be able to like the post once
-# Load post model (using streamID)
type Post @loadModel(id: "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96") {
id: ID!
}
# New comment model
# Set reference to original post
# Enable querying comment to get original post
type Comment @createModel(accountRelation: LIST, description: "A comment on a Post") {
postID: StreamID! @documentReference(model: "Post")
post: Post! @relationDocument(property: "postID")
text: String! @string(maxLength: 500)
}
# New like model
# Set relationship to original post
# Enable querying comment to get original post
type Like @createModel(description: "A like on a post", accountRelation: SET, accountRelationFields: ["postID"]) {
postID: StreamID! @documentReference(model: "Post")
post: Post! @relationDocument(property: "postID")
}
# Load post model (using streamID)
type Post @loadModel(id: "kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy") {
id: ID!
}
# New comment model
# Set reference to original post
# Enable querying comment to get original post
type Comment @createModel(accountRelation: LIST, description: "A comment on a Post") {
postID: StreamID! @documentReference(model: "Post")
post: Post! @relationDocument(property: "postID")
text: String! @string(maxLength: 500)
}
# New like model
# Set relationship to original post
# Enable querying comment to get original post
type Like @createModel(description: "A like on a post", accountRelation: SET, accountRelationFields: ["postID"]) {
postID: StreamID! @documentReference(model: "Post")
post: Post! @relationDocument(property: "postID")
}
Relations can also be created between models loaded from known streamIDs
-# Load comment model
type Comment @loadModel(id: "kjzl6hvfrbw6c9oo2ync09y6z5c9mas9u49lfzcowepuzxmcn3pzztvzd0c7gh0") {
id: ID!
}
# Load post model
# Extend post model with comments and likes
# Set relationships to all comments and likes
# Enable querying post to get all comments and likes
type Post @loadModel(id: "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96") {
comments: [Comment] @relationFrom(model: "Comment", property: "postID")
likes: [Like] @relationFrom(model: "Like", property: "postID")
}
# Load comment model
type Comment @loadModel(id: "kjzl6hvfrbw6c9oo2ync09y6z5c9mas9u49lfzcowepuzxmcn3pzztvzd0c7gh0") {
id: ID!
}
# Load post model
# Extend post model with comments and likes
# Set relationships to all comments and likes
# Enable querying post to get all comments and likes
type Post @loadModel(id: "kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy") {
comments: [Comment] @relationFrom(model: "Comment", property: "postID")
likes: [Like] @relationFrom(model: "Like", property: "postID")
}
Where:
id
is a simple placeholder, since empty types are not allowedceramic-one
using the following command:ceramic-one daemon
By default, the command above will spin off a node which connects to a clay-testnet
network. You can change this behaviour by providing a --network
flag and specifying a network of your choice. For example:
ceramic-one daemon --network clay-testnet
By default, the command above will spin off a node which connects to a testnet-clay
network. You can change this behaviour by providing a --network
flag and specifying a network of your choice. For example:
ceramic-one daemon --network testnet-clay
By default ceramic-one
will store its data in the current directory. You can configure this behaviour by
specifying the --store-dir
and --p2p-key-dir
arguments. For example:
ceramic-one daemon --store-dir ~/.ceramic-one --p2p-key-dir ~/.ceramic-one