From 4fbf2ac83a27f9164eef098ce651650b3d1d7e98 Mon Sep 17 00:00:00 2001 From: Elias Datler Date: Mon, 10 Mar 2025 09:56:55 +0100 Subject: [PATCH 1/6] Method to export multiple projects --- service/saved/Saved.mo | 69 ++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/service/saved/Saved.mo b/service/saved/Saved.mo index 8831e3c9..e919fcdb 100644 --- a/service/saved/Saved.mo +++ b/service/saved/Saved.mo @@ -2,11 +2,13 @@ import Time "mo:base/Time"; import Trie "mo:base/Trie"; import Nat "mo:base/Nat"; import Nat32 "mo:base/Nat32"; +import Buffer "mo:base/Buffer"; +import Iter "mo:base/Iter"; import Prim "mo:⛔"; import Types "Types"; -actor { +shared ({ caller = owner }) actor class Saved() { public type Project = Types.MotokoProject; @@ -19,13 +21,11 @@ actor { // Represents a set of saved projects, using their hashes. // (But rather than store this type directly, we use ProjectTable instead.) - public type Projects = - Trie.Trie; + public type Projects = Trie.Trie; /// Indexes a set of Projects; permits lookup by hash, /// without knowing the "full project" as a key. - public type ProjectTable = - Trie.Trie; + public type ProjectTable = Trie.Trie; func hashProject(p : Project) : (Nat32, Nat) { // TODO input validation, e.g. duplicate filenames @@ -37,7 +37,7 @@ actor { let c : Nat32 = Prim.charToNat32(char); x := ((x << 5) +% x) +% c; }; - x + x; }; // Hash is only computed based on files. Packages and canisters // are considered as configs which can be updated with the same code. @@ -46,14 +46,14 @@ actor { x := hashCont(x, file.content); size += file.content.size() + file.name.size(); }; - (x, size) + (x, size); }; stable var stableProjects : ProjectTable = Trie.empty(); stable var byteSize : Nat = 0; public func putProject(p : Project) : async HashId { - let (hashId, size) = hashProject(p); + let (hashId, size) = hashProject(p); let key = { key = Nat32.toNat(hashId); hash = hashId }; let saved = { timestamp = Time.now(); @@ -61,28 +61,53 @@ actor { }; let (ps, existing) = Trie.replace(stableProjects, key, Nat.equal, ?saved); switch existing { - case (?_) {}; - case null { - byteSize += size; - }; + case (?_) {}; + case null { + byteSize += size; + }; }; stableProjects := ps; - key.key + key.key; }; public query func getProject(hashId : HashId) : async ?SavedProject { let key = { hash = Nat32.fromNat(hashId); key = hashId }; - Trie.find(stableProjects, key, Nat.equal) + Trie.find(stableProjects, key, Nat.equal); }; type StatResult = { - num_projects: Nat; - byte_size: Nat; + num_projects : Nat; + byte_size : Nat; }; public query func getStats() : async StatResult { - { - num_projects = Trie.size(stableProjects); - byte_size = byteSize; - } - } -} + { + num_projects = Trie.size(stableProjects); + byte_size = byteSize; + }; + }; + + public query ({ caller }) func getProjectsPage(start : Nat, size : Nat) : async [(HashId, SavedProject)] { + assert (owner == caller); + let iter = Trie.iter(stableProjects); + + for (i in Iter.range(0, start - 1)) { + let _ = iter.next(); + }; + + let result = Buffer.Buffer<(HashId, SavedProject)>(size); + + label l for (i in Iter.range(start, start + size - 1)) { + let item = iter.next(); + switch item { + case (?some) { + result.add(some); + }; + case null { + break l; + }; + }; + }; + + return Buffer.toArray(result); + }; +}; From 13fb211e1c7d1020bc6e4d9933fa9ec89c30267f Mon Sep 17 00:00:00 2001 From: Elias Datler Date: Wed, 12 Mar 2025 17:13:15 +0100 Subject: [PATCH 2/6] dfx generate --- src/declarations/saved/saved.did | 81 ++++++++++++++------------- src/declarations/saved/saved.did.d.ts | 12 ++-- src/declarations/saved/saved.did.js | 8 ++- 3 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/declarations/saved/saved.did b/src/declarations/saved/saved.did index 7a09bf76..918ea3c6 100644 --- a/src/declarations/saved/saved.did +++ b/src/declarations/saved/saved.did @@ -1,42 +1,43 @@ type Time = int; -type StatResult = - record { - byte_size: nat; - num_projects: nat; - }; -type SavedProject = - record { - project: Project; - timestamp: Time; - }; -type Project = - record { - canisters: opt vec CanisterInfo; - files: vec NamedFile; - packages: opt vec PackageInfo; - }; -type PackageInfo = - record { - dir: opt text; - homepage: opt text; - name: text; - repo: text; - version: text; - }; -type NamedFile = - record { - content: text; - name: text; - }; +type StatResult = record { + byte_size : nat; + num_projects : nat; +}; +type SavedProject = record { + project : Project; + timestamp : Time; +}; +type Saved = service { + getProject : (HashId) -> (opt SavedProject) query; + getProjectsPage : (nat, nat) -> ( + vec record { + HashId; + SavedProject; + } + ) query; + getStats : () -> (StatResult) query; + putProject : (Project) -> (HashId); +}; +type Project = record { + canisters : opt vec CanisterInfo; + files : vec NamedFile; + packages : opt vec PackageInfo; +}; +type PackageInfo = record { + dir : opt text; + homepage : opt text; + name : text; + repo : text; + version : text; +}; +type NamedFile = record { + content : text; + name : text; +}; type HashId = nat; -type CanisterInfo = - record { - candid: text; - id: principal; - name: text; - }; -service : { - getProject: (HashId) -> (opt SavedProject) query; - getStats: () -> (StatResult) query; - putProject: (Project) -> (HashId); -} +type CanisterInfo = record { + candid : text; + id : principal; + name : text; +}; +service : () -> Saved; diff --git a/src/declarations/saved/saved.did.d.ts b/src/declarations/saved/saved.did.d.ts index 684be8da..666cd7fe 100644 --- a/src/declarations/saved/saved.did.d.ts +++ b/src/declarations/saved/saved.did.d.ts @@ -24,6 +24,12 @@ export interface Project { packages: [] | [Array]; canisters: [] | [Array]; } +export interface Saved { + getProject: ActorMethod<[HashId], [] | [SavedProject]>; + getProjectsPage: ActorMethod<[bigint, bigint], Array<[HashId, SavedProject]>>; + getStats: ActorMethod<[], StatResult>; + putProject: ActorMethod<[Project], HashId>; +} export interface SavedProject { timestamp: Time; project: Project; @@ -33,10 +39,6 @@ export interface StatResult { num_projects: bigint; } export type Time = bigint; -export interface _SERVICE { - getProject: ActorMethod<[HashId], [] | [SavedProject]>; - getStats: ActorMethod<[], StatResult>; - putProject: ActorMethod<[Project], HashId>; -} +export interface _SERVICE extends Saved {} export declare const idlFactory: IDL.InterfaceFactory; export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; diff --git a/src/declarations/saved/saved.did.js b/src/declarations/saved/saved.did.js index 23603879..0e0b6082 100644 --- a/src/declarations/saved/saved.did.js +++ b/src/declarations/saved/saved.did.js @@ -24,11 +24,17 @@ export const idlFactory = ({ IDL }) => { byte_size: IDL.Nat, num_projects: IDL.Nat, }); - return IDL.Service({ + const Saved = IDL.Service({ getProject: IDL.Func([HashId], [IDL.Opt(SavedProject)], ["query"]), + getProjectsPage: IDL.Func( + [IDL.Nat, IDL.Nat], + [IDL.Vec(IDL.Tuple(HashId, SavedProject))], + ["query"], + ), getStats: IDL.Func([], [StatResult], ["query"]), putProject: IDL.Func([Project], [HashId], []), }); + return Saved; }; export const init = ({ IDL }) => { return []; From ec546da7cbcc3db3c134d0890afc506e89107003 Mon Sep 17 00:00:00 2001 From: Elias Datler Date: Wed, 12 Mar 2025 17:15:27 +0100 Subject: [PATCH 3/6] update --- src/declarations/saved/saved.did | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/declarations/saved/saved.did b/src/declarations/saved/saved.did index 918ea3c6..f5ccd27d 100644 --- a/src/declarations/saved/saved.did +++ b/src/declarations/saved/saved.did @@ -7,17 +7,6 @@ type SavedProject = record { project : Project; timestamp : Time; }; -type Saved = service { - getProject : (HashId) -> (opt SavedProject) query; - getProjectsPage : (nat, nat) -> ( - vec record { - HashId; - SavedProject; - } - ) query; - getStats : () -> (StatResult) query; - putProject : (Project) -> (HashId); -}; type Project = record { canisters : opt vec CanisterInfo; files : vec NamedFile; @@ -40,4 +29,14 @@ type CanisterInfo = record { id : principal; name : text; }; -service : () -> Saved; +service : { + getProject : (HashId) -> (opt SavedProject) query; + getProjectsPage : (nat, nat) -> ( + vec record { + HashId; + SavedProject; + } + ) query; + getStats : () -> (StatResult) query; + putProject : (Project) -> (HashId); +};; From c34d1aefa85f707b65eb76de195a7ad7cbc26681 Mon Sep 17 00:00:00 2001 From: Elias Datler Date: Thu, 13 Mar 2025 15:05:50 +0100 Subject: [PATCH 4/6] Address feedback --- service/saved/Saved.mo | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/service/saved/Saved.mo b/service/saved/Saved.mo index e919fcdb..378201ca 100644 --- a/service/saved/Saved.mo +++ b/service/saved/Saved.mo @@ -87,27 +87,20 @@ shared ({ caller = owner }) actor class Saved() { }; public query ({ caller }) func getProjectsPage(start : Nat, size : Nat) : async [(HashId, SavedProject)] { - assert (owner == caller); + assert owner == caller; let iter = Trie.iter(stableProjects); for (i in Iter.range(0, start - 1)) { - let _ = iter.next(); + ignore iter.next(); }; let result = Buffer.Buffer<(HashId, SavedProject)>(size); label l for (i in Iter.range(start, start + size - 1)) { - let item = iter.next(); - switch item { - case (?some) { - result.add(some); - }; - case null { - break l; - }; - }; + let ?item = iter.next() else break l; + result.add(item); }; - return Buffer.toArray(result); + Buffer.toArray(result); }; }; From 71dc75f16d48729cf4840dcc40a1a7474c5df10b Mon Sep 17 00:00:00 2001 From: Gabor Greif Date: Thu, 13 Mar 2025 15:11:42 +0100 Subject: [PATCH 5/6] Create .prettierrc --- .prettierrc | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..edacc171 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "overrides": [ + { + "files": "*.mo", + "options": { + "tabWidth": 2, + "semi": false, + "trailingComma": "none" + } + } + ] +} From ad1a300ec633cb53ea452fbbc407f2748408e360 Mon Sep 17 00:00:00 2001 From: Elias Datler Date: Thu, 13 Mar 2025 15:14:09 +0100 Subject: [PATCH 6/6] New format --- service/saved/Saved.mo | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/service/saved/Saved.mo b/service/saved/Saved.mo index 378201ca..e3d410c9 100644 --- a/service/saved/Saved.mo +++ b/service/saved/Saved.mo @@ -16,7 +16,7 @@ shared ({ caller = owner }) actor class Saved() { public type SavedProject = { timestamp : Time.Time; - project : Project; + project : Project }; // Represents a set of saved projects, using their hashes. @@ -35,18 +35,18 @@ shared ({ caller = owner }) actor class Saved() { var x = x_; for (char in text.chars()) { let c : Nat32 = Prim.charToNat32(char); - x := ((x << 5) +% x) +% c; + x := ((x << 5) +% x) +% c }; - x; + x }; // Hash is only computed based on files. Packages and canisters // are considered as configs which can be updated with the same code. for (file in p.files.vals()) { x := hashCont(x, file.name); x := hashCont(x, file.content); - size += file.content.size() + file.name.size(); + size += file.content.size() + file.name.size() }; - (x, size); + (x, size) }; stable var stableProjects : ProjectTable = Trie.empty(); @@ -57,33 +57,33 @@ shared ({ caller = owner }) actor class Saved() { let key = { key = Nat32.toNat(hashId); hash = hashId }; let saved = { timestamp = Time.now(); - project = p; + project = p }; let (ps, existing) = Trie.replace(stableProjects, key, Nat.equal, ?saved); switch existing { case (?_) {}; case null { - byteSize += size; - }; + byteSize += size + } }; stableProjects := ps; - key.key; + key.key }; public query func getProject(hashId : HashId) : async ?SavedProject { let key = { hash = Nat32.fromNat(hashId); key = hashId }; - Trie.find(stableProjects, key, Nat.equal); + Trie.find(stableProjects, key, Nat.equal) }; type StatResult = { num_projects : Nat; - byte_size : Nat; + byte_size : Nat }; public query func getStats() : async StatResult { { num_projects = Trie.size(stableProjects); - byte_size = byteSize; - }; + byte_size = byteSize + } }; public query ({ caller }) func getProjectsPage(start : Nat, size : Nat) : async [(HashId, SavedProject)] { @@ -91,16 +91,16 @@ shared ({ caller = owner }) actor class Saved() { let iter = Trie.iter(stableProjects); for (i in Iter.range(0, start - 1)) { - ignore iter.next(); + ignore iter.next() }; let result = Buffer.Buffer<(HashId, SavedProject)>(size); label l for (i in Iter.range(start, start + size - 1)) { let ?item = iter.next() else break l; - result.add(item); + result.add(item) }; - Buffer.toArray(result); - }; -}; + Buffer.toArray(result) + } +}