From ac4afb4f927bf77d3a3e9812bcf5a5abccb6f598 Mon Sep 17 00:00:00 2001 From: Hunter Perrin Date: Fri, 14 Jun 2024 11:33:11 -0700 Subject: [PATCH] Update package pages and user guides with new features. --- src/routes/packages/client-node/+page.svelte | 4 +- src/routes/packages/client/+page.svelte | 4 +- src/routes/packages/guid/+page.svelte | 2 - src/routes/packages/nymph/+page.svelte | 17 ++--- src/routes/packages/pubsub/+page.svelte | 8 +-- src/routes/packages/query-parser/+page.svelte | 36 +++++------ src/routes/packages/server/+page.svelte | 12 ++-- .../packages/tilmeld-client/+page.svelte | 4 +- .../packages/tilmeld-components/+page.svelte | 2 +- .../packages/tilmeld-setup/+page.svelte | 6 +- src/routes/packages/tilmeld/+page.svelte | 5 +- .../user-guide/defining-entities/+page.svelte | 64 ++++++++----------- 12 files changed, 74 insertions(+), 90 deletions(-) diff --git a/src/routes/packages/client-node/+page.svelte b/src/routes/packages/client-node/+page.svelte index a6e0f6f..2ae8719 100644 --- a/src/routes/packages/client-node/+page.svelte +++ b/src/routes/packages/client-node/+page.svelte @@ -9,8 +9,8 @@

- The Nymph Node Client let's you do everything the Nymph Client does, but - from Node.JS instead of the browser. + The Nymph Node Client lets you do everything the Nymph Client does, but from + Node.JS instead of the browser.

diff --git a/src/routes/packages/client/+page.svelte b/src/routes/packages/client/+page.svelte index 359d316..ceee3d1 100644 --- a/src/routes/packages/client/+page.svelte +++ b/src/routes/packages/client/+page.svelte @@ -77,7 +77,7 @@ let subscription = pubsub.subscribeEntities( { type: '&', '!tag': 'archived', - } + }, )( (update) => { // The first time this is called, \`update\` will be an array of Todo @@ -95,7 +95,7 @@ let subscription = pubsub.subscribeEntities( // If you provide this callback, the server will send updates of how many // clients are subscribed to this query. userCount = count; - } + }, ); // ... diff --git a/src/routes/packages/guid/+page.svelte b/src/routes/packages/guid/+page.svelte index 6e04eb6..ba47957 100644 --- a/src/routes/packages/guid/+page.svelte +++ b/src/routes/packages/guid/+page.svelte @@ -61,6 +61,4 @@ const customId = customAlphabet('abc', 20)();`} import bash from 'svelte-highlight/languages/bash'; import typescript from 'svelte-highlight/languages/typescript'; import github from 'svelte-highlight/styles/github'; - - import { base } from '$app/paths'; diff --git a/src/routes/packages/nymph/+page.svelte b/src/routes/packages/nymph/+page.svelte index ff1faa6..f8cbabe 100644 --- a/src/routes/packages/nymph/+page.svelte +++ b/src/routes/packages/nymph/+page.svelte @@ -27,7 +27,8 @@ To use Nymph, you need a database driver. Nymph.js provides a MySQL driver, PostgreSQL driver, and a - SQLite3 driver. + SQLite3 driver. They all + provide the exact same functionality.

@@ -65,7 +66,7 @@ async function run() { const otherPendingTodos = await nymph.getEntities( { class: Todo }, - { type: '&', '!guid': myEntity.guid, equal: ['done', false] } + { type: '&', '!guid': myEntity.guid, equal: ['done', false] }, ); const total = otherPendingTodos.length; @@ -73,7 +74,7 @@ async function run() { console.log( \`Besides the one I just created, there \${ single ? 'is' : 'are' - } \${total} pending todo\${single ? '' : 's'} in the database.\` + } \${total} pending todo\${single ? '' : 's'} in the database.\`, ); }`} /> @@ -92,14 +93,6 @@ export default class Todo extends Entity { static ETYPE = 'todo'; // This is used for the table name(s) in the DB. static class = 'Todo'; // This is used to map references to their class. - static async factory(guid?: string): Promise { - return (await super.factory(guid)) as Todo & TodoData; - } - - static factorySync(): Todo & TodoData { - return super.factorySync() as Todo & TodoData; - } - constructor() { super(); @@ -115,7 +108,7 @@ export default class Todo extends Entity { // instance of Nymph, so it could be a transactional instance. const otherTodos = await this.$nymph.getEntities( { class: Todo }, - { type: '!&', guid: this.guid } + { type: '!&', guid: this.guid }, ); return otherTodos; } diff --git a/src/routes/packages/pubsub/+page.svelte b/src/routes/packages/pubsub/+page.svelte index 581227e..0636397 100644 --- a/src/routes/packages/pubsub/+page.svelte +++ b/src/routes/packages/pubsub/+page.svelte @@ -45,7 +45,7 @@ const nymph = new Nymph( {}, new SQLite3Driver({ filename: ':memory:', // Put the correct driver/config here. - }) + }), ); PubSub.initPublisher(pubSubConfig, nymph);`} /> @@ -74,7 +74,7 @@ const nymph = new Nymph( {}, new SQLite3Driver({ filename: ':memory:', // Put the correct driver/config here. - }) + }), ); // Don't forget to do this; even here! PubSub.initPublisher(pubSubConfig, nymph); @@ -108,7 +108,7 @@ const nymph = new Nymph( {}, new SQLite3Driver({ filename: ':memory:', // Put the correct driver/config here. - }) + }), ); // Don't forget to do this; even here! PubSub.initPublisher(pubSubConfig, nymph); @@ -122,7 +122,7 @@ const server = http.createServer((_request, response) => { const listener = server.listen(port, () => { console.log( new Date().toISOString(), - \`Nymph-PubSub server started listening on port \${port}.\` + \`Nymph-PubSub server started listening on port \${port}.\`, ); }); const wsServer = new WebSocketServer({ diff --git a/src/routes/packages/query-parser/+page.svelte b/src/routes/packages/query-parser/+page.svelte index 5a30d7b..89a7e29 100644 --- a/src/routes/packages/query-parser/+page.svelte +++ b/src/routes/packages/query-parser/+page.svelte @@ -100,7 +100,7 @@ async function doQuery() { />
-

Usage

+

Options

You can set limit, offset, sort, and reverse like this.

@@ -172,7 +172,7 @@ async function doQuery() {

Check for a tag.

    -
  • <tag> or <!tag>
  • +
  • {''} or {''}
@@ -206,7 +206,7 @@ async function doQuery() { {'name<{refclassname inner query}>'} or {'name!<{refclassname inner query}>'}
    -
  • (Esacpe curly brackets with a leading backslash.)
  • +
  • (Escape curly brackets with a leading backslash.)
  • (Requires a map of refclassname to their actual class and default fields.) @@ -306,9 +306,9 @@ async function doQuery() {

    Check a prop's value is greater than a given value.

      -
    • name>number
    • +
    • {'name>number'}
    • - name>relative + {'name>relative'}
      • (A single relative time value like now or @@ -317,7 +317,7 @@ async function doQuery() {
    • - name>"relative time value" + {'name>"relative time value"'}
      • (Use this for a time value with a space like Check a prop's value is greater than or equal to a given value.

          -
        • name>=number
        • +
        • {'name>=number'}
        • - name>=relative + {'name>=relative'}
          • (A single relative time value like now or @@ -348,7 +348,7 @@ async function doQuery() {
        • - name>="relative time value" + {'name>="relative time value"'}
          • (Use this for a time value with a space like Check a prop's value is less than a given value.

              -
            • name<number
            • +
            • {'name
            • - name<relative + {'name
              • (A single relative time value like now or @@ -379,7 +379,7 @@ async function doQuery() {
            • - name<"relative time value" + {'name<"relative time value"'}
              • (Use this for a time value with a space like Check a prop's value is less than or equal to a given value.

                  -
                • name<=number
                • +
                • {'name<=number'}
                • - name<=relative + {'name<=relative'}
                  • (A single relative time value like now or @@ -410,7 +410,7 @@ async function doQuery() {
                • - name<="relative time value" + {'name<="relative time value"'}
                  • (Use this for a time value with a space like Here are some examples of nested selectors.

                    -
                    Either enabled is truthy and abilities contains "subscriber", or abilities contains "lifelong-subscriber".
                    +  
                    {`Either enabled is truthy and abilities contains "subscriber", or abilities contains "lifelong-subscriber".
                     
                    -(| ([enabled] abilities<"subscriber">) abilities<"lifeline-subscriber">)
                    +(| ([enabled] abilities<"subscriber">) abilities<"lifeline-subscriber">)
                     
                     
                     Published is not truthy and cdate is not greater than 6 months ago.
                     
                    -(! [published] cdate>"6 months ago")
                    +(! [published] cdate>"6 months ago")`}

                    Default Fields

                    diff --git a/src/routes/packages/server/+page.svelte b/src/routes/packages/server/+page.svelte index 634f9ce..188690d 100644 --- a/src/routes/packages/server/+page.svelte +++ b/src/routes/packages/server/+page.svelte @@ -46,7 +46,7 @@ const nymph = new Nymph( {}, new SQLite3Driver({ filename: ':memory:', - }) + }), ); const MyEntity = nymph.addEntityClass(MyEntityClass); @@ -68,8 +68,8 @@ app.listen(80);`}

                    - Now you can configure your client using your server's address - (and the optional path, if set). + Now you can configure your client, using your server's + address (and the optional path, if set).

                    The Tilmeld client contains the client versions of the User and Group - entities. It also contains helpers, getClientConfig, - login, register, and checkUsername. + entities. It also contains helpers, login, + register, and checkUsername.

                    diff --git a/src/routes/packages/tilmeld-components/+page.svelte b/src/routes/packages/tilmeld-components/+page.svelte index fe68db1..8280af8 100644 --- a/src/routes/packages/tilmeld-components/+page.svelte +++ b/src/routes/packages/tilmeld-components/+page.svelte @@ -10,7 +10,7 @@

                    The Tilmeld Components are front end registration/login, account recovery, - account details, and password change components build with Svelte diff --git a/src/routes/packages/tilmeld-setup/+page.svelte b/src/routes/packages/tilmeld-setup/+page.svelte index 0b0ee95..fed4ae7 100644 --- a/src/routes/packages/tilmeld-setup/+page.svelte +++ b/src/routes/packages/tilmeld-setup/+page.svelte @@ -70,7 +70,7 @@ const nymph = new Nymph( verifyChangeRedirect: 'http://localhost', cancelChangeRedirect: 'http://localhost', jwtSecret: 'shhhhh', - }) + }), ); // Create your Express app. @@ -86,8 +86,8 @@ app.use( { restUrl: 'http://localhost/rest', }, - nymph - ) + nymph, + ), ); // Do anything else you need to do... diff --git a/src/routes/packages/tilmeld/+page.svelte b/src/routes/packages/tilmeld/+page.svelte index 9e031ac..9ee0ee8 100644 --- a/src/routes/packages/tilmeld/+page.svelte +++ b/src/routes/packages/tilmeld/+page.svelte @@ -57,7 +57,7 @@ const nymph = new Nymph( new SQLite3Driver({ filename: ':memory:', }), - tilmeld + tilmeld, ); // These are the classes specific to this instance of Tilmeld. @@ -84,7 +84,8 @@ const { User, Group } = tilmeld;`}

                    • - system/admin - A user with this ability has **all** abilities. + system/admin - A user with this ability has + all abilities.
                    • tilmeld/admin - Allow the user to manage and edit other user's diff --git a/src/routes/user-guide/defining-entities/+page.svelte b/src/routes/user-guide/defining-entities/+page.svelte index 8f4b013..bd8034b 100644 --- a/src/routes/user-guide/defining-entities/+page.svelte +++ b/src/routes/user-guide/defining-entities/+page.svelte @@ -21,7 +21,11 @@
                      Extending Entity in Node.js
                      { protected $protectedTags = ['archived']; protected $allowlistTags? = []; - static async factory(guid?: string): Promise { - return (await super.factory(guid)) as Todo & TodoData; - } - - static factorySync(): Todo & TodoData { - return super.factorySync() as Todo & TodoData; - } - constructor() { super(); @@ -54,6 +50,11 @@ export class Todo extends Entity { this.$data.done = false; } + async $getUniques() { + // Make sure this isn't a duplicate Todo for this user. + return [\`\${this.$data.user.guid}:\${this.$data.name}\`]; + } + async $archive() { if (this.$hasTag('archived')) { return true; @@ -81,26 +82,14 @@ export class Todo extends Entity { 'Invalid Todo: ' ); - // Check that this is not a duplicate Todo. - const selector: Selector = { - type: '&', - equal: ['name', this.$data.name], - }; - if (this.guid) { - selector['!guid'] = this.guid; + try { + return await super.$save(); + } catch (e: any) { + if (e instanceof EntityUniqueConstraintError) { + throw new Error('There is already a todo for that.'); + } + throw e; } - if ( - await this.$nymph.getEntity( - { - class: this.$nymph.getEntityClass(Todo), - }, - selector - ) - ) { - throw new Error('There is already a todo for that.'); - } - - return await super.$save(); } } @@ -125,14 +114,6 @@ export class Todo extends Entity { // The name of the server class public static class = 'Todo'; - static async factory(guid?: string): Promise { - return (await super.factory(guid)) as Todo & TodoData; - } - - static factorySync(): Todo & TodoData { - return super.factorySync() as Todo & TodoData; - } - constructor() { super(); @@ -197,6 +178,17 @@ const Todo = nymph.addEntityClass(TodoClass);`} maps the client class to the Node.js class and vice versa.

                      +

                      + Nymph provides a mechanism to ensure uniqueness among entities. Any strings + returned by the $getUniques method will have a uniqueness + constraint enforced by the database across this entity's etype. The + Todo class returns a string containing both the user's GUID and + the todo name. This ensures that the user can't have two todos with the same + name. The $save method checks for a thrown + EntityUniqueConstraintError + when calling the super class' $save. +

                      +

                      Finally, in Node.js, the Todo class validates all of its data in the $save method using