Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sqlite): add sqlite support #291

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

no-on3
Copy link

@no-on3 no-on3 commented Feb 3, 2025

this #287
Tests fixed.

@muco-rolle
Copy link

Thank you @animir for bringing the support of SQLite. When is this planned to be released?

}


_upsert(rlKey, points, msDuration, forceExpire = false) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@no-on3 Hello, can you make it atomic upsert?

All limiters from this package do atomic upserts. If there is no way to implement the same with SQLite, please, rename the class to RateLimiterSQLiteNonAtomic.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe SQLite supports atomic upserts. Here's how the code would look. I haven't tested it in depth, but if @no-on3 isn't available, I'd be happy to look into it and add it.

_upsert(rlKey, points, msDuration, forceExpire = false) {
    if (!this.tableCreated) {
      return Promise.reject(Error("Table is not created yet"));
    }

    return new Promise((resolve, reject) => {
      const dateNow = Date.now();
      const newExpire = msDuration > 0 ? dateNow + msDuration : null;

      this.client.serialize(() => {
        this.client.run("BEGIN TRANSACTION", (err) => {
          if (err) return reject(err);

          let query, params;

          if (forceExpire) {
            query = `
            INSERT INTO ${this.tableName} (key, points, expire)
            VALUES (?, ?, ?)
            ON CONFLICT(key) DO UPDATE SET
              points = excluded.points,
              expire = excluded.expire
          `;
            params = [rlKey, points, newExpire];
          } else {
            query = `
            INSERT INTO ${this.tableName} (key, points, expire)
            VALUES (?, ?, ?)
            ON CONFLICT(key) DO UPDATE SET
              points = CASE
                WHEN (expire > ? OR expire IS NULL) THEN points + excluded.points
                ELSE excluded.points
              END,
              expire = CASE
                WHEN (expire > ? OR expire IS NULL) THEN expire
                ELSE excluded.expire
              END
          `;
            params = [rlKey, points, newExpire, dateNow, dateNow];
          }

          this.client.run(query, params, (errUpsert) => {
            if (errUpsert) {
              this.client.run("ROLLBACK");
              return reject(errUpsert);
            }

            this.client.get(
              `SELECT points, expire FROM ${this.tableName} WHERE key = ?`,
              [key],
              (errSelect, result) => {
                if (errSelect) {
                  this.client.run("ROLLBACK");
                  return reject(errSelect);
                }

                this.client.run("COMMIT", (errCommit) => {
                  if (errCommit) {
                    this.client.run("ROLLBACK");
                    return reject(errCommit);
                  }
                  resolve(result || { points, expire: newExpire });
                });
              }
            );
          });
        });
      });
    });
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants