npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

yact

v0.2.0

Published

Yet another change tracker for SQL. Creates an audit log that tracks all changes to a database table.

Downloads

6

Readme

yact

Yet another change tracker for SQL tables. Most software systems require a Change Tracker component for the auditors. This component should record the 5Ws (who, when, where, why and what) of any database table change.

Microsoft's SQL Server has an out of the box solution called Change Data Capture, which is great. However, you need an Enterprise license to enable this feature and its very expensive; at least for us startups and open sorcerers. yact implements a poor man's change tracking by using SQL triggers to insert an audit row.

yact's twist is to store the before and after images of the change as XML content as opposed to most other implementations that add a row for each field that was changed. I believe this gives a light weight and flexible (read efficient) to change tracking.

Getting started

Install with npm

> npm install -g yact

Generate the script for the table triggers and the audit table into yact.sql

> yact -a Employee Payroll

Usage

> yact -help
Usage: yact-cl [options] [table[:key]...]

 Generate the audit trigger script for the table(s)

 Options:

   -h, --help           output usage information
   -V, --version        output the version number
   -a, --audit          include the script to create the Audit table
   -i, --individual     save the script(s) as individual files.
   -o, --output [file]  save the script(s) to the specified file, the default is "yact.sql"

 Examples:

   # create trigger script for contact table, primary key is contact_id
   yact contact

   # create trigger script for contact table, primary key is id
   yact contact:id

The trigger

The magic in the trigger is to join the inserted and deleted tables and then convert the rows to XML. These tables are supplied by the SQL server when the trigger is invoked. Each table has the same columns as table_name.

insert into audit (table_name, old_content, new_content) 
  select 
    @table_name,
    case when d.table_id is null then null else (select d.* for xml raw) end,
    case when i.table_id is null then null else (select i.* for xml raw) end
  from inserted as i
    full outer join deleted as d on i.table_id = d.table_id

All you need to change is

  • declare\set @table_name
  • change table_id to the name of table's primary key.

Caveat Emptor

Triggers that insert (as yact does) change the @@identity value. All stored procedures should at least use scope_identity() instead of @@identity; see how not to retrieve identity value for more issues.

audit table

All changes (insert, update or delete) to a yact monitored table are stored in the audit table.

| Column | Description | | ------ | ----------- | | audit_id | A unique key for this audit entry. Keeps an ORM happy. | | operation | The SQL operation (insert, update or delete) performed on the table_name. | | table_name | What information was changed. | | old_content | What was the old information; formatted as XML. Each column of the row is an XML attribute. | | new_content | What is the new information; foratted as XML. Each column of the row is an XML attribute. | | who | Who changed this information. | | when | When was the information changed. |
| where | Where was the change performed from (IP address of the SQL client). | | why | Why was this change performed. Not yet implemented. |

Who are you

Identity is hard, queue Keith Moon's drum roll. yact uses the system_user for the default who value. This is appopriate for client/server (2-tier) systems; where each user logs into the database. But, for most 3-tier systems, the server has its own account for the database. In this scenario the who must be supplied by the trigger.

Many 3-tier systems have a modifiedBy column in each table. In this case the trigger can be changed to use this column

insert into audit (table_name, who, old_content, new_content) 
  select 
    @table_name,
    IsNull(i.modifiedBy, d.ModifiedBy),
    case when d.table_id is null then null else (select d.* for xml raw) end,
    case when i.table_id is null then null else (select i.* for xml raw) end
  from inserted as i
    full outer join deleted as d on i.table_id = d.table_id

Time is relative

yact defaults when to sysdatetimeoffset, which includes the time zone offset of the SQL server. This works if all users are in the same time zone. If the software system has the user's time, then this value should be used in trigger's insert.

By using the time zone offset, its possible to determine if the user accessed the system after working hours.

However, its not possible to determine if the user accessed the system during a public holiday.