Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions snd/history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# snd module history

**TL;DR:** the `snd` module's full commit history travels with it on every migration. **File-level** history and blame work everywhere — GitHub, IntelliJ, and any tool that follows renames (Sourcetree, GitKraken, Fork, GitLens, `git log --follow`, etc.). **Directory-level** history (`git log -- snd/` or GitHub's directory tree view) only shows commits since the most recent migration — for older directory-level browsing, open the corresponding repo from the table below.

## Why directory-level history is limited

Each migration changed the path of the module — first from a repo root into a subdirectory, then between subdirectories. Git's rename detection is per-file, not per-directory, so a directory-level log starts fresh at each move even though every individual file's history remains intact.

## Where prior history lives

| Repository | History active | Notes |
|------------------------------------------------------------------------------------------------------------------|-------------------------|--------------------------------------------------------------------------|
| [LabKey/snd](https://github.com/LabKey/snd) | until 2025-02-24 | Original standalone repo. Now archived. |
| [LabKey/ehrModules/snd](https://github.com/LabKey/ehrModules/tree/fc811d93c1a99ee46e219508da17041a9bcfb2d4/snd) | 2025-02-24 → 2026-05-05 | Rehomed via `LabKey/ehrModules` commit `76b86bc5` ("Rehome snd module"). |
| [LabKey/snprcEHRModules/snd](https://github.com/LabKey/snprcEHRModules/tree/develop/snd) | 2026-05-05 → present | Current home. Rehomed from `LabKey/ehrModules`. |

## Browsing history

### File-level (works everywhere)

Any Git tool that follows renames will show full history back to the module's origin:

- **GitHub**: open any individual file, then click *History* or *Blame*. GitHub follows renames automatically across migrations.
- **IntelliJ**: right-click a file → *Git → Show History* (or *Annotate* for blame).
- **Other tools** (Sourcetree, GitKraken, Fork, GitLens, etc.): use the file's history or blame view — these tools follow renames by default.
- **CLI**: `git log --follow -- <path/to/file>`.

### Directory-level (use the table above)

There is no built-in equivalent to `--follow` for directories. To see directory-level history from before a migration, open the corresponding repo from the table above for the date range you care about and browse the module directory there.
2 changes: 1 addition & 1 deletion snd/resources/queries/snd/DeletedLookupSets.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
select
substring(qae.oldrecordmap, charindex('objectid=',qae.oldrecordmap, 0) + len('objectid='), 36) as objectid,
substring(qae.oldrecordmap, locate('objectid=', qae.oldrecordmap) + length('objectid='), 36) as objectid,
qae.date as modified

from auditLog.QueryUpdateAuditEvent as qae
Expand Down
2 changes: 1 addition & 1 deletion snd/resources/queries/snd/DeletedLookups.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
select
substring(qae.oldrecordmap, charindex('objectid=',qae.oldrecordmap, 0) + len('objectid='), 36) as objectid,
substring(qae.oldrecordmap, locate('objectid=', qae.oldrecordmap) + length('objectid='), 36) as objectid,
qae.date as modified

from auditLog.QueryUpdateAuditEvent as qae
Expand Down
88 changes: 66 additions & 22 deletions snd/resources/schemas/dbscripts/postgresql/snd-0.000-25.000.sql
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,16 @@ CREATE INDEX IDX_SND_EVENTSCACHE_CONTAINER ON snd.EventsCache(Container);
-- Creation date: 9/22/2017
-- Description: Table valued function to return hierarchical view of a superPkg
-- ==========================================================================================
-- NOTE: ROW_NUMBER() OVER (...) cannot be used in the recursive term of WITH RECURSIVE in
-- PostgreSQL. The TreePath is computed using SortOrder directly, which preserves ordering
-- semantics while remaining compatible with PostgreSQL's recursive CTE restrictions.
-- NOTE: PostgreSQL forbids window functions in the recursive term of WITH RECURSIVE. We
-- pre-compute per-parent ordinals (ROW_NUMBER PARTITION BY ParentSuperPkgId) in a
-- non-recursive CTE that is materialized once, then join to it in both the anchor and
-- recursive members. This produces a stable per-parent TreePath segment and avoids the
-- collisions and 3-char truncation that result from formatting raw SortOrder values.
-- This differs from the SQL Server twin (sqlserver/snd-0.000-25.000.sql), which uses an
-- unpartitioned ROW_NUMBER OVER (ORDER BY SortOrder); the partitioned form is preferred
-- and the MSSQL function should eventually be aligned. NULLS FIRST is used so a NULL
-- SortOrder sorts first within a parent, matching MSSQL's default NULL-ordering and the
-- prior PG behavior (COALESCE(SortOrder, 0)).
-- ==========================================================================================
CREATE FUNCTION snd.fGetSuperPkg(_pkgId INT)
RETURNS TABLE (
Expand All @@ -337,14 +344,26 @@ RETURNS TABLE (
Level INTEGER
)
LANGUAGE sql AS $$
WITH RECURSIVE CTE1 (TopLevelPkgId, SuperPkgId, ParentSuperPkgId, PkgId, TreePath, SuperPkgPath, SortOrder, Required, Description, Narrative, Active, Repeatable, Level) AS (
WITH RECURSIVE
ordered_super_pkgs AS (
SELECT sp.SuperPkgId,
sp.ParentSuperPkgId,
sp.PkgId,
sp.SuperPkgPath,
sp.SortOrder,
sp.Required,
ROW_NUMBER() OVER (PARTITION BY sp.ParentSuperPkgId
ORDER BY sp.SortOrder NULLS FIRST, sp.SuperPkgId) AS Ordinal
FROM snd.SuperPkgs sp
),
CTE1 (TopLevelPkgId, SuperPkgId, ParentSuperPkgId, PkgId, TreePath, SuperPkgPath, SortOrder, Required, Description, Narrative, Active, Repeatable, Level) AS (

-- anchor member
SELECT _pkgId::INTEGER AS TopLevelPkgId,
sp.SuperPkgId,
sp.ParentSuperPkgId,
sp.PkgId,
RIGHT(REPEAT(' ', 3) || COALESCE(sp.SortOrder, 0)::VARCHAR, 3) AS TreePath,
LPAD(sp.Ordinal::TEXT, 6, '0') AS TreePath,
sp.SuperPkgPath,
sp.SortOrder,
sp.Required,
Expand All @@ -353,7 +372,7 @@ LANGUAGE sql AS $$
p.Active,
p.Repeatable,
1 AS Level
FROM snd.SuperPkgs sp
FROM ordered_super_pkgs sp
INNER JOIN snd.Pkgs p ON sp.PkgId = p.PkgId
WHERE sp.PkgId = _pkgId
AND sp.ParentSuperPkgId IS NULL
Expand All @@ -365,7 +384,7 @@ LANGUAGE sql AS $$
sp.SuperPkgId,
c.SuperPkgId AS ParentSuperPkgId,
sp.PkgId,
c.TreePath || '/' || RIGHT(REPEAT(' ', 3) || COALESCE(sp.SortOrder, 0)::VARCHAR, 3) AS TreePath,
c.TreePath || '/' || LPAD(sp.Ordinal::TEXT, 6, '0') AS TreePath,
sp.SuperPkgPath,
sp.SortOrder,
sp.Required,
Expand All @@ -374,7 +393,7 @@ LANGUAGE sql AS $$
p.Active,
p.Repeatable,
c.Level + 1 AS Level
FROM snd.SuperPkgs AS sp
FROM ordered_super_pkgs AS sp
INNER JOIN CTE1 AS c ON
sp.ParentSuperPkgId = c.SuperPkgId
OR sp.ParentSuperPkgId IN (
Expand Down Expand Up @@ -407,6 +426,12 @@ $$;
-- Description: Returns the list of ProjectItems for a Project/Revision along with
-- sub packages for each ProjectItem
-- ==========================================================================================
-- See note on fGetSuperPkg above re: pre-computed ordinals. The anchor uses an ordinal
-- ordered by (ProjectItemId, SuperPkgId), which matches the MSSQL anchor's ROW_NUMBER.
-- The recursive sub-tree uses per-parent ordinals over (SortOrder NULLS FIRST,
-- SuperPkgId) -- partitioned by ParentSuperPkgId, unlike MSSQL's unpartitioned form;
-- NULLS FIRST matches MSSQL's default NULL-ordering.
-- ==========================================================================================
CREATE FUNCTION snd.fGetProjectItems(_projectId INT, _revisionNum INT)
RETURNS TABLE (
ProjectId INTEGER,
Expand All @@ -421,27 +446,46 @@ RETURNS TABLE (
Description VARCHAR
)
LANGUAGE sql AS $$
WITH RECURSIVE CTE1 (ProjectId, RevisionNum, ProjectItemId, ParentObjectId, ParentSuperPkgId, SuperPkgId, PkgId, ProjectActive, Active, TreePath, Level, Description) AS (
WITH RECURSIVE
ordered_project_items AS (
SELECT pi.ProjectItemId,
pi.ParentObjectId,
pi.SuperPkgId,
pi.Active AS ItemActive,
p.Active AS ProjectActive,
ROW_NUMBER() OVER (ORDER BY pi.ProjectItemId, pi.SuperPkgId) AS Ordinal
FROM snd.ProjectItems pi
INNER JOIN snd.Projects p ON pi.ParentObjectId = p.ObjectId
WHERE p.ProjectId = _projectId
AND p.RevisionNum = _revisionNum
),
ordered_super_pkgs AS (
SELECT sp.SuperPkgId,
sp.ParentSuperPkgId,
sp.PkgId,
sp.SortOrder,
ROW_NUMBER() OVER (PARTITION BY sp.ParentSuperPkgId
ORDER BY sp.SortOrder NULLS FIRST, sp.SuperPkgId) AS Ordinal
FROM snd.SuperPkgs sp
),
CTE1 (ProjectId, RevisionNum, ProjectItemId, ParentObjectId, ParentSuperPkgId, SuperPkgId, PkgId, ProjectActive, Active, TreePath, Level, Description) AS (

-- anchor member
SELECT _projectId::INTEGER AS ProjectId,
_revisionNum::INTEGER AS RevisionNum,
pi.ProjectItemId,
pi.ParentObjectId,
opi.ProjectItemId,
opi.ParentObjectId,
sp.ParentSuperPkgId,
sp.SuperPkgId,
sp.PkgId,
p.Active AS ProjectActive,
pi.Active,
RIGHT(REPEAT(' ', 3) || COALESCE(sp.SuperPkgId, 0)::VARCHAR, 3) AS TreePath,
opi.ProjectActive,
opi.ItemActive AS Active,
LPAD(opi.Ordinal::TEXT, 6, '0') AS TreePath,
1 AS Level,
pkg.Description
FROM snd.ProjectItems AS pi
INNER JOIN snd.Projects AS p ON pi.ParentObjectId = p.ObjectId
INNER JOIN snd.SuperPkgs AS sp ON pi.SuperPkgId = sp.SuperPkgId
FROM ordered_project_items AS opi
INNER JOIN snd.SuperPkgs AS sp ON opi.SuperPkgId = sp.SuperPkgId
INNER JOIN snd.Pkgs pkg ON sp.PkgId = pkg.PkgId
WHERE p.ProjectId = _projectId
AND p.RevisionNum = _revisionNum

UNION ALL

Expand All @@ -455,10 +499,10 @@ LANGUAGE sql AS $$
sp.PkgId,
c.ProjectActive,
c.Active,
c.TreePath || '/' || RIGHT(REPEAT(' ', 3) || COALESCE(sp.SortOrder, 0)::VARCHAR, 3) AS TreePath,
c.Level + 1 AS Level,
c.TreePath || '/' || LPAD(sp.Ordinal::TEXT, 6, '0') AS TreePath,
c.Level + 1 AS Level,
pkg.Description
FROM snd.SuperPkgs AS sp
FROM ordered_super_pkgs AS sp
INNER JOIN snd.Pkgs AS pkg ON sp.PkgId = pkg.PkgId
INNER JOIN CTE1 AS c ON
sp.ParentSuperPkgId = c.SuperPkgId
Expand Down
16 changes: 5 additions & 11 deletions snd/src/org/labkey/snd/SNDManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -1549,20 +1549,14 @@ public void createProject(Container c, User u, Project project, BatchValidationE
}
}

/**
* Used in reviseProject to update a project
*/

//TODO: Use QUS to update columns - pass Project.objectId
// Note: EndDate is the only field that's updated with this
private void updateProjectField(Container c, User u, int id, int rev, String field, Object value)
private void updateProjectEndDate(Container c, User u, int id, int rev, Object endDate)
{
UserSchema schema = getSndUserSchema(c, u);

SQLFragment sql = new SQLFragment("UPDATE " + SNDSchema.getInstance().getTableInfoProjects());
sql.append(" SET " + field + " = ?");
sql.append(" WHERE ProjectId = ? AND RevisionNum = ?");
sql.add(value).add(id).add(rev);
sql.append(" SET EndDate = ? WHERE ProjectId = ? AND RevisionNum = ?");
sql.add(endDate).add(id).add(rev);

new SqlExecutor(schema.getDbSchema().getScope()).execute(sql);
}
Expand All @@ -1578,8 +1572,8 @@ public void reviseProject(Container c, User u, Project project, BatchValidationE
UserSchema schema = getSndUserSchema(c, u);
List<Map<String, Object>> updatedProjectItems = new ArrayList<>();

updateProjectField(c, u, project.getProjectId(), project.getRevisionNum(), "EndDate",
project.getEndDateRevised() == null ? null : project.getEndDateRevised());
updateProjectEndDate(c, u, project.getProjectId(), project.getRevisionNum(),
project.getEndDateRevised());

if (project.isCopyRevisedPkgs())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ ALTER VIEW [labkey_etl].[v_charge_account] AS
-- 11/11/2016 added modified, modifiedby, created, and createdby columns tjh
-- 10/22/2019 removed distinct clause from valid_charge_by_species join tjh
-- 02/15/2020 Added fallback for missing created & createdBy columns tjh
-- 04/23/2026 Removed join on species table and added OUTER APPLY ja
-- ==========================================================================================


Expand All @@ -47,7 +48,12 @@ ALTER VIEW [labkey_etl].[v_charge_account] AS
ca.timestamp AS timestamp
FROM dbo.charge_account AS ca
LEFT OUTER JOIN dbo.TAC_COLUMNS AS tc ON tc.object_id = ca.object_id
LEFT OUTER JOIN dbo.valid_charge_by_species AS vcs ON ca.charge_id = vcs.charge_id
OUTER APPLY (
SELECT TOP 1 vcs2.charge_id, vcs2.arc_species_code
FROM dbo.valid_charge_by_species vcs2
WHERE vcs2.charge_id = ca.charge_id
ORDER BY vcs2.arc_species_code
) vcs
LEFT OUTER JOIN dbo.prd_cost_account AS pca on pca.account_id = ca.account_id


Expand Down
Loading