Merged in feature/textExtractionsPart1 (pull request #192)

all schema and rest apis for text extraction support

* in progress

* stage 8 complete

* phase 9 completed

* phase 9 complete

* ongoing - s3 path fix

* working

* optimize ci build

* e2e tests

* missing test
This commit is contained in:
Jay Brown
2025-11-26 19:23:42 +00:00
parent 2b43799f56
commit c45e1dd427
67 changed files with 16120 additions and 817 deletions
@@ -0,0 +1,5 @@
-- Rollback: Drop folders table and its indexes
DROP INDEX IF EXISTS idx_folders_path;
DROP INDEX IF EXISTS idx_folders_clientid;
DROP INDEX IF EXISTS idx_folders_parentid;
DROP TABLE IF EXISTS folders;
@@ -0,0 +1,18 @@
-- Create folders table for hierarchical document organization
CREATE TABLE folders (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
path text NOT NULL,
parentId uuid,
clientId varchar(255) NOT NULL,
createdAt timestamp NOT NULL DEFAULT NOW(),
createdBy varchar(255) NOT NULL,
FOREIGN KEY (parentId) REFERENCES folders(id),
FOREIGN KEY (clientId) REFERENCES clients(clientId),
UNIQUE(clientId, path),
CHECK (id != parentId)
);
-- Indexes for efficient folder queries
CREATE INDEX idx_folders_parentid ON folders(parentId);
CREATE INDEX idx_folders_clientid ON folders(clientId);
CREATE INDEX idx_folders_path ON folders(path);
@@ -0,0 +1,7 @@
-- Rollback: Drop documentLabels and labels tables with indexes
DROP INDEX IF EXISTS idx_documentlabels_document_label_time;
DROP INDEX IF EXISTS idx_documentlabels_appliedat;
DROP INDEX IF EXISTS idx_documentlabels_label;
DROP INDEX IF EXISTS idx_documentlabels_documentid;
DROP TABLE IF EXISTS documentLabels;
DROP TABLE IF EXISTS labels;
@@ -0,0 +1,31 @@
-- Create labels lookup table
CREATE TABLE labels (
label text PRIMARY KEY,
description text NOT NULL
);
-- Seed initial label values
INSERT INTO labels (label, description) VALUES
('Ingested', 'Document has been ingested into the system'),
('OCR_Processed', 'OCR text extraction completed'),
('GenAI_Processed', 'GenAI processing completed'),
('Doczy_AI_Completed', 'Doczy.AI processing completed'),
('Dashboard_Ready', 'Document ready for dashboard display');
-- Create documentLabels junction table
CREATE TABLE documentLabels (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
documentId uuid NOT NULL,
label text NOT NULL,
appliedAt timestamp NOT NULL DEFAULT NOW(),
appliedBy varchar(255) NOT NULL,
FOREIGN KEY (documentId) REFERENCES documents(id) ON DELETE CASCADE,
FOREIGN KEY (label) REFERENCES labels(label)
);
-- Indexes for efficient label queries
CREATE INDEX idx_documentlabels_documentid ON documentLabels(documentId);
CREATE INDEX idx_documentlabels_label ON documentLabels(label);
CREATE INDEX idx_documentlabels_appliedat ON documentLabels(appliedAt);
-- Composite index for finding most recent label application
CREATE INDEX idx_documentlabels_document_label_time ON documentLabels(documentId, label, appliedAt DESC);
@@ -0,0 +1,18 @@
-- Rollback: Remove folderId, originalPath columns and related constraints/indexes from documents table
-- Remove comments from folders table
COMMENT ON COLUMN folders.path IS NULL;
COMMENT ON TABLE folders IS NULL;
-- Remove comments from documentEntries table
COMMENT ON COLUMN documentEntries.bucket IS NULL;
COMMENT ON COLUMN documentEntries.key IS NULL;
-- Remove originalPath column
COMMENT ON COLUMN documents.originalPath IS NULL;
ALTER TABLE documents DROP COLUMN IF EXISTS originalPath;
-- Remove folderId column
DROP INDEX IF EXISTS idx_documents_folderid;
ALTER TABLE documents DROP CONSTRAINT IF EXISTS fk_documents_folderid;
ALTER TABLE documents DROP COLUMN IF EXISTS folderId;
@@ -0,0 +1,29 @@
-- Add folderId column to documents table for folder organization
-- Note: filename column already exists from migration 105
ALTER TABLE documents ADD COLUMN folderId uuid;
-- Add foreign key constraint to folders table
ALTER TABLE documents ADD CONSTRAINT fk_documents_folderid
FOREIGN KEY (folderId) REFERENCES folders(id);
-- Add index for efficient folder-based document queries
CREATE INDEX idx_documents_folderid ON documents(folderId);
-- Add originalPath column to store the exact path provided during upload
-- This value is IMMUTABLE after creation - it preserves the original upload path
-- even if the document is later moved to a different virtual folder
ALTER TABLE documents ADD COLUMN originalPath text;
COMMENT ON COLUMN documents.originalPath IS
'Original path provided during upload. IMMUTABLE after creation - never modify this value.';
-- Add comments to clarify immutability of S3 storage fields
COMMENT ON COLUMN documentEntries.key IS
'S3 object key. IMMUTABLE after creation - never modify this value.';
COMMENT ON COLUMN documentEntries.bucket IS
'S3 bucket name. IMMUTABLE after creation - never modify this value.';
-- Add comment to clarify that folders are virtual (database-only, no S3 relationship)
COMMENT ON TABLE folders IS
'Virtual folder hierarchy for document organization. Database-only - has no direct relationship to S3 storage locations.';
COMMENT ON COLUMN folders.path IS
'Virtual folder path (e.g., "/contracts/2025"). Can be renamed without affecting S3 storage.';
@@ -0,0 +1,5 @@
-- Rollback: Drop documentFieldExtractions table and its indexes
DROP INDEX IF EXISTS idx_documentfieldextractions_filename;
DROP INDEX IF EXISTS idx_documentfieldextractions_createdby;
DROP INDEX IF EXISTS idx_documentfieldextractions_documentid;
DROP TABLE IF EXISTS documentFieldExtractions;
@@ -0,0 +1,48 @@
-- Create documentFieldExtractions table for single-value fields
CREATE TABLE documentFieldExtractions (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
documentId uuid NOT NULL,
-- Single-value fields (19 fields total - 1:1 relationship)
-- Document identification
fileName text,
contractTitle text,
aareteDerivedAmendmentNum int,
-- Party information
clientName text,
payerName text,
payerState text,
providerState text,
-- Tax identification numbers (stored as text to preserve leading zeros)
filenameTin text,
provGroupTin text,
provGroupNpi text,
provGroupNameFull text,
provOtherTin text,
provOtherNpi text,
provOtherNameFull text,
-- Contract dates
aareteDerivedEffectiveDt date,
aareteDerivedTerminationDt date,
-- Renewal information
autoRenewalInd boolean,
autoRenewalTerm text,
-- Metadata
createdAt timestamp NOT NULL DEFAULT NOW(),
createdBy varchar(255) NOT NULL,
FOREIGN KEY (documentId) REFERENCES documents(id)
);
-- Indexes for efficient queries
CREATE INDEX idx_documentfieldextractions_documentid
ON documentFieldExtractions(documentId);
CREATE INDEX idx_documentfieldextractions_createdby
ON documentFieldExtractions(createdBy);
CREATE INDEX idx_documentfieldextractions_filename
ON documentFieldExtractions(fileName);
@@ -0,0 +1,4 @@
-- Rollback: Drop documentFieldExtractionVersions table and its indexes
DROP INDEX IF EXISTS idx_documentfieldextractionversions_version;
DROP INDEX IF EXISTS idx_documentfieldextractionversions_fieldextractionid;
DROP TABLE IF EXISTS documentFieldExtractionVersions;
@@ -0,0 +1,16 @@
-- Create documentFieldExtractionVersions table for version tracking
CREATE TABLE documentFieldExtractionVersions (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
fieldExtractionId uuid NOT NULL,
version bigint NOT NULL,
createdBy varchar(255) NOT NULL,
createdAt timestamp NOT NULL DEFAULT NOW(),
FOREIGN KEY (fieldExtractionId) REFERENCES documentFieldExtractions(id)
);
-- Indexes for version queries
CREATE INDEX idx_documentfieldextractionversions_fieldextractionid
ON documentFieldExtractionVersions(fieldExtractionId);
CREATE INDEX idx_documentfieldextractionversions_version
ON documentFieldExtractionVersions(version);
@@ -0,0 +1,4 @@
-- Rollback: Drop documentFieldExtractionArrayFields table and its indexes
DROP INDEX IF EXISTS idx_documentfieldextractionarrayfields_id_index;
DROP INDEX IF EXISTS idx_documentfieldextractionarrayfields_fieldextractionid;
DROP TABLE IF EXISTS documentFieldExtractionArrayFields;
@@ -0,0 +1,173 @@
-- Create documentFieldExtractionArrayFields table for 1:N array fields
CREATE TABLE documentFieldExtractionArrayFields (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
fieldExtractionId uuid NOT NULL,
arrayIndex smallint NOT NULL,
-- Array-value fields (112 fields total - 1:N relationship)
-- All fields at same arrayIndex form one "row" of the array
-- Exhibit information
exhibitTitle text,
exhibitPage text,
-- Reimbursement provider information
reimbProvTin text,
reimbProvNpi text,
reimbProvName text,
reimbEffectiveDt date,
reimbTerminationDt date,
-- Claim and product codes
aareteDerivedClaimTypeCd text,
aareteDerivedProduct text,
aareteDerivedLob text,
aareteDerivedProgram text,
aareteDerivedNetwork text,
aareteDerivedProvType text,
-- Provider taxonomy and specialty
provTaxonomyCd text,
provTaxonomyCdDesc text,
provSpecialtyCd text,
provSpecialtyCdDesc text,
-- Service location
placeOfServiceCd text,
placeOfServiceCdDesc text,
billTypeCd text,
billTypeCdDesc text,
-- Patient demographics
patientAgeMin text,
patientAgeMax text,
-- Reimbursement terms
reimbTerm text,
lobProgramRelationship text,
lobProductRelationship text,
-- Carveout and payment logic
carveoutInd boolean,
carveoutCd text,
lesserOfInd boolean,
greaterOfInd boolean,
aareteDerivedReimbMethod text,
unitOfMeasure text,
-- Reimbursement rates
reimbPctRate numeric(10,4),
reimbFeeRate numeric(12,2),
reimbConversionFactor numeric(12,4),
triggerCapThresholdAmt numeric(12,2),
triggerBaseThreshold numeric(12,2),
-- Default and addition
defaultInd boolean,
additionDesc text,
additionMaxFeeRateInc numeric(12,2),
additionMaxPctRateInc numeric(10,4),
aareteDerivedAdditionRateChangeTimeline text,
-- Fee schedule
aareteDerivedFeeSchedule text,
aareteDerivedFeeScheduleVersion text,
-- Service codes
serviceTerm text,
cpt4ProcCd text,
cpt4ProcCdDesc text,
cpt4ProcMod text,
cpt4ProcModDesc text,
revenueCd text,
revenueCdDesc text,
diagCd text,
diagCdDesc text,
ndcCd text,
ndcCdDesc text,
-- Claim admit and status
claimAdmitTypeCd text,
authAdmitTypeDesc text,
claimStatusCd text,
claimStatusCdDesc text,
-- Grouper information
grouperType text,
grouperCd text,
grouperCdDesc text,
grouperPctRate numeric(10,4),
grouperBaseRate numeric(12,2),
aareteDerivedGrouperVersion text,
grouperAlternativeLevelOfCare text,
grouperSeverityInd boolean,
grouperSeverity text,
grouperRiskOfMortalitySubclass text,
grouperTransferInd boolean,
grouperReadmissionsInd boolean,
grouperHacInd boolean,
-- Outlier terms
outlierTerm text,
outlierFirstDollarInd boolean,
rangeNbrDays text,
outlierFixedLossNbrDaysThreshold numeric(10,2),
outlierFixedLossThreshold numeric(12,2),
outlierMaximum numeric(12,2),
outlierMaximumFrequency numeric(10,2),
outlierPctRate numeric(10,4),
outlierExclusionCd text,
outlierExclusionCdDesc text,
-- Facility adjustments
facilityAdjustmentTerm text,
dshInd boolean,
dshPctRate numeric(10,4),
dshFeeRate numeric(12,2),
imeInd boolean,
imePctRate numeric(10,4),
imeFeeRate numeric(12,2),
ntapInd boolean,
ntapPctRate numeric(10,4),
ntapFeeRate numeric(12,2),
ucInd boolean,
ucPctRate numeric(10,4),
ucFeeRate numeric(12,2),
gmeInd boolean,
gmePctRate numeric(10,4),
gmeFeeRate numeric(12,2),
-- Rate escalator
rateEscalatorInd boolean,
rateEscalatorDesc text,
rateEscalatorMaxRateIncPct numeric(10,4),
rateEscalatorRateChangeTimeline numeric(10,2),
-- Stop loss
stopLossTerm text,
stopLossFirstDollarInd boolean,
stopLossRangeNbrDays numeric(10,2),
stopLossFixedLossThreshold numeric(12,2),
stopLossMaximum numeric(12,2),
stopLossMaximumFrequency numeric(10,2),
stopLossDailyMaxRate numeric(12,2),
stopLossPctRateOnExcessCharges numeric(10,4),
stopLossExclusionCd text,
stopLossExclusionDesc text,
FOREIGN KEY (fieldExtractionId) REFERENCES documentFieldExtractions(id),
-- Ensure unique index per extraction
UNIQUE (fieldExtractionId, arrayIndex),
-- Ensure arrayIndex is non-negative
CHECK (arrayIndex >= 0)
);
-- Indexes for efficient array field queries
CREATE INDEX idx_documentfieldextractionarrayfields_fieldextractionid
ON documentFieldExtractionArrayFields(fieldExtractionId);
-- Composite index for efficient ordered retrieval
CREATE INDEX idx_documentfieldextractionarrayfields_id_index
ON documentFieldExtractionArrayFields(fieldExtractionId, arrayIndex);
@@ -0,0 +1,3 @@
-- Rollback: Drop field extraction views
DROP VIEW IF EXISTS currentFieldExtractionsWithArrayCount;
DROP VIEW IF EXISTS currentFieldExtractions;
@@ -0,0 +1,44 @@
-- Create view for current (newest) field extraction per document
CREATE VIEW currentFieldExtractions AS
SELECT DISTINCT ON (dfe.documentId)
dfe.id,
dfe.documentId,
dfe.fileName,
dfe.contractTitle,
dfe.aareteDerivedAmendmentNum,
dfe.clientName,
dfe.payerName,
dfe.payerState,
dfe.providerState,
dfe.filenameTin,
dfe.provGroupTin,
dfe.provGroupNpi,
dfe.provGroupNameFull,
dfe.provOtherTin,
dfe.provOtherNpi,
dfe.provOtherNameFull,
dfe.aareteDerivedEffectiveDt,
dfe.aareteDerivedTerminationDt,
dfe.autoRenewalInd,
dfe.autoRenewalTerm,
dfev.version,
dfev.createdBy,
dfev.createdAt
FROM documentFieldExtractions dfe
JOIN documentFieldExtractionVersions dfev
ON dfev.fieldExtractionId = dfe.id
ORDER BY dfe.documentId, dfev.id DESC;
-- Create extended view with array field count
CREATE VIEW currentFieldExtractionsWithArrayCount AS
SELECT
cfe.*,
COALESCE(array_counts.arraySize, 0) as arraySize
FROM currentFieldExtractions cfe
LEFT JOIN (
SELECT
fieldExtractionId,
COUNT(*) as arraySize
FROM documentFieldExtractionArrayFields
GROUP BY fieldExtractionId
) array_counts ON array_counts.fieldExtractionId = cfe.id;
@@ -0,0 +1,4 @@
-- Remove folder_id column from documentUploads table
DROP INDEX IF EXISTS idx_documentuploads_folder_id;
ALTER TABLE documentUploads DROP CONSTRAINT IF EXISTS fk_documentuploads_folder_id;
ALTER TABLE documentUploads DROP COLUMN IF EXISTS folder_id;
@@ -0,0 +1,6 @@
-- Add folder_id column to documentUploads table to persist folder association during batch uploads
ALTER TABLE documentUploads ADD COLUMN folder_id uuid;
-- Add foreign key constraint referencing folders table
ALTER TABLE documentUploads ADD CONSTRAINT fk_documentuploads_folder_id FOREIGN KEY (folder_id) REFERENCES folders(id);
-- Add index for efficient lookup by folder
CREATE INDEX idx_documentuploads_folder_id ON documentUploads(folder_id);
+4 -4
View File
@@ -34,7 +34,7 @@ SELECT id, hash from documents where clientId = @clientId;
SELECT id, hash, filename from documents where batch_id = @batch_id;
-- name: CreateDocument :one
INSERT INTO documents (clientId, hash, batch_id, filename) VALUES ($1, $2, $3, $4) RETURNING id;
INSERT INTO documents (clientId, hash, batch_id, filename, folderId, originalPath) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id;
-- name: AddDocumentEntry :exec
INSERT INTO documentEntries (documentId, bucket, key) VALUES ($1, $2, $3);
@@ -49,13 +49,13 @@ SELECT id FROM documents WHERE hash = $1 and clientId = $2;
SELECT id, totalCount FROM listDocumentIDs(@clientId, @batchSize, @pageOffset);
-- name: AddDocumentUpload :exec
INSERT INTO documentUploads (id, clientId, bucket, key, part, createdAt, filename, batch_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8);
INSERT INTO documentUploads (id, clientId, bucket, key, part, createdAt, filename, batch_id, folder_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);
-- name: GetDocumentUploadByKey :one
SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id FROM documentUploads WHERE bucket = $1 AND key = $2 LIMIT 1;
SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id, folder_id FROM documentUploads WHERE bucket = $1 AND key = $2 LIMIT 1;
-- name: ListDocumentUploads :many
SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id FROM documentUploads WHERE clientId = $1 ORDER BY createdAt;
SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id, folder_id FROM documentUploads WHERE clientId = $1 ORDER BY createdAt;
-- name: GetDocumentUploadCurrentPart :one
WITH client as (
@@ -0,0 +1,202 @@
-- name: AddFieldExtraction :one
INSERT INTO documentFieldExtractions (
documentId,
fileName,
contractTitle,
aareteDerivedAmendmentNum,
clientName,
payerName,
payerState,
providerState,
filenameTin,
provGroupTin,
provGroupNpi,
provGroupNameFull,
provOtherTin,
provOtherNpi,
provOtherNameFull,
aareteDerivedEffectiveDt,
aareteDerivedTerminationDt,
autoRenewalInd,
autoRenewalTerm,
createdBy
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10,
$11, $12, $13, $14, $15, $16, $17, $18, $19, $20
)
RETURNING *;
-- name: AddFieldExtractionArrayField :exec
INSERT INTO documentFieldExtractionArrayFields (
fieldExtractionId,
arrayIndex,
exhibitTitle,
exhibitPage,
reimbProvTin,
reimbProvNpi,
reimbProvName,
reimbEffectiveDt,
reimbTerminationDt,
aareteDerivedClaimTypeCd,
aareteDerivedProduct,
aareteDerivedLob,
aareteDerivedProgram,
aareteDerivedNetwork,
aareteDerivedProvType,
provTaxonomyCd,
provTaxonomyCdDesc,
provSpecialtyCd,
provSpecialtyCdDesc,
placeOfServiceCd,
placeOfServiceCdDesc,
billTypeCd,
billTypeCdDesc,
patientAgeMin,
patientAgeMax,
reimbTerm,
lobProgramRelationship,
lobProductRelationship,
carveoutInd,
carveoutCd,
lesserOfInd,
greaterOfInd,
aareteDerivedReimbMethod,
unitOfMeasure,
reimbPctRate,
reimbFeeRate,
reimbConversionFactor,
triggerCapThresholdAmt,
triggerBaseThreshold,
defaultInd,
additionDesc,
additionMaxFeeRateInc,
additionMaxPctRateInc,
aareteDerivedAdditionRateChangeTimeline,
aareteDerivedFeeSchedule,
aareteDerivedFeeScheduleVersion,
serviceTerm,
cpt4ProcCd,
cpt4ProcCdDesc,
cpt4ProcMod,
cpt4ProcModDesc,
revenueCd,
revenueCdDesc,
diagCd,
diagCdDesc,
ndcCd,
ndcCdDesc,
claimAdmitTypeCd,
authAdmitTypeDesc,
claimStatusCd,
claimStatusCdDesc,
grouperType,
grouperCd,
grouperCdDesc,
grouperPctRate,
grouperBaseRate,
aareteDerivedGrouperVersion,
grouperAlternativeLevelOfCare,
grouperSeverityInd,
grouperSeverity,
grouperRiskOfMortalitySubclass,
grouperTransferInd,
grouperReadmissionsInd,
grouperHacInd,
outlierTerm,
outlierFirstDollarInd,
rangeNbrDays,
outlierFixedLossNbrDaysThreshold,
outlierFixedLossThreshold,
outlierMaximum,
outlierMaximumFrequency,
outlierPctRate,
outlierExclusionCd,
outlierExclusionCdDesc,
facilityAdjustmentTerm,
dshInd,
dshPctRate,
dshFeeRate,
imeInd,
imePctRate,
imeFeeRate,
ntapInd,
ntapPctRate,
ntapFeeRate,
ucInd,
ucPctRate,
ucFeeRate,
gmeInd,
gmePctRate,
gmeFeeRate,
rateEscalatorInd,
rateEscalatorDesc,
rateEscalatorMaxRateIncPct,
rateEscalatorRateChangeTimeline,
stopLossTerm,
stopLossFirstDollarInd,
stopLossRangeNbrDays,
stopLossFixedLossThreshold,
stopLossMaximum,
stopLossMaximumFrequency,
stopLossDailyMaxRate,
stopLossPctRateOnExcessCharges,
stopLossExclusionCd,
stopLossExclusionDesc
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10,
$11, $12, $13, $14, $15, $16, $17, $18, $19, $20,
$21, $22, $23, $24, $25, $26, $27, $28, $29, $30,
$31, $32, $33, $34, $35, $36, $37, $38, $39, $40,
$41, $42, $43, $44, $45, $46, $47, $48, $49, $50,
$51, $52, $53, $54, $55, $56, $57, $58, $59, $60,
$61, $62, $63, $64, $65, $66, $67, $68, $69, $70,
$71, $72, $73, $74, $75, $76, $77, $78, $79, $80,
$81, $82, $83, $84, $85, $86, $87, $88, $89, $90,
$91, $92, $93, $94, $95, $96, $97, $98, $99, $100,
$101, $102, $103, $104, $105, $106, $107, $108, $109, $110,
$111, $112, $113, $114
);
-- name: AddFieldExtractionEntry :exec
INSERT INTO documentFieldExtractionVersions (fieldExtractionId, version, createdBy)
VALUES ($1, $2, $3);
-- name: GetCurrentFieldExtraction :one
SELECT * FROM currentFieldExtractions
WHERE documentId = $1;
-- name: GetCurrentFieldExtractionWithArrayCount :one
SELECT * FROM currentFieldExtractionsWithArrayCount
WHERE documentId = $1;
-- name: GetFieldExtractionArrayFields :many
SELECT * FROM documentFieldExtractionArrayFields
WHERE fieldExtractionId = $1
ORDER BY arrayIndex;
-- name: GetFieldExtractionHistory :many
SELECT
dfe.id,
dfe.documentId,
dfev.version,
dfev.createdBy,
dfev.createdAt
FROM documentFieldExtractions dfe
JOIN documentFieldExtractionVersions dfev
ON dfev.fieldExtractionId = dfe.id
WHERE dfe.documentId = $1
ORDER BY dfev.version DESC;
-- name: ValidateArrayFieldCount :one
SELECT COUNT(*) as arrayFieldCount
FROM documentFieldExtractionArrayFields
WHERE fieldExtractionId = $1;
-- name: GetFieldExtractionByID :one
SELECT * FROM documentFieldExtractions
WHERE id = $1;
-- name: GetFieldExtractionsByDocumentID :many
SELECT * FROM documentFieldExtractions
WHERE documentId = $1
ORDER BY createdAt DESC;
+89
View File
@@ -0,0 +1,89 @@
-- name: CreateFolder :one
INSERT INTO folders (path, parentId, clientId, createdBy)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: GetFolderByID :one
SELECT * FROM folders
WHERE id = $1;
-- name: GetFolderByPath :one
SELECT * FROM folders
WHERE clientId = $1 AND path = $2;
-- name: GetFoldersByClientID :many
SELECT * FROM folders
WHERE clientId = $1
ORDER BY path;
-- name: GetFoldersByParentID :many
SELECT * FROM folders
WHERE parentId = $1
ORDER BY path;
-- name: RenameFolder :exec
UPDATE folders
SET path = $2
WHERE id = $1;
-- name: GetFolderTree :many
WITH RECURSIVE folder_tree AS (
-- Base case: start with the target folder
SELECT id, path, parentId, clientId, createdAt, createdBy
FROM folders
WHERE id = $1
UNION ALL
-- Recursive case: find all child folders
SELECT f.id, f.path, f.parentId, f.clientId, f.createdAt, f.createdBy
FROM folders f
INNER JOIN folder_tree ft ON f.parentId = ft.id
)
SELECT id, path, parentId, clientId, createdAt, createdBy
FROM folder_tree
ORDER BY path;
-- name: GetRootFolders :many
-- Returns folders with null parentId (should only be the "/" root folder for each client)
SELECT * FROM folders
WHERE clientId = $1 AND parentId IS NULL
ORDER BY path;
-- name: GetTopLevelFolders :many
-- Returns folders that are direct children of the root folder "/"
-- These are the user-visible top-level folders (e.g., /folder1, /folder2)
SELECT f.* FROM folders f
INNER JOIN folders root ON f.parentId = root.id
WHERE f.clientId = $1 AND root.path = '/'
ORDER BY f.path;
-- name: GetClientRootFolder :one
-- Returns the root folder "/" for a client
SELECT * FROM folders
WHERE clientId = $1 AND path = '/';
-- name: GetDocumentsByFolder :many
SELECT * FROM documents
WHERE folderId = $1
ORDER BY id;
-- name: CountDocumentsByFolder :one
SELECT COUNT(*) as total FROM documents
WHERE folderId = $1;
-- name: GetFolderLabelCounts :many
SELECT dl.label, COUNT(DISTINCT dl.documentId) as count
FROM documents d
INNER JOIN documentLabels dl ON d.id = dl.documentId
WHERE d.folderId = $1
GROUP BY dl.label
ORDER BY dl.label;
-- name: UpsertFolder :one
-- Insert a folder if it doesn't exist, or return the existing one
-- Used for auto-creating folder hierarchies during document upload
INSERT INTO folders (path, parentId, clientId, createdBy)
VALUES ($1, $2, $3, $4)
ON CONFLICT (clientId, path) DO UPDATE SET path = EXCLUDED.path
RETURNING *;
+46
View File
@@ -0,0 +1,46 @@
-- name: ApplyLabel :one
INSERT INTO documentLabels (documentId, label, appliedBy)
VALUES ($1, $2, $3)
RETURNING *;
-- name: GetDocumentLabels :many
SELECT * FROM documentLabels
WHERE documentId = $1
ORDER BY appliedAt DESC;
-- name: GetMostRecentLabel :one
SELECT * FROM documentLabels
WHERE documentId = $1 AND label = $2
ORDER BY appliedAt DESC
LIMIT 1;
-- name: GetDocumentsByLabel :many
SELECT DISTINCT d.*
FROM documents d
INNER JOIN documentLabels dl ON d.id = dl.documentId
WHERE d.clientId = $1 AND dl.label = $2
ORDER BY d.id;
-- name: GetDocumentsByLabelAndFolder :many
SELECT DISTINCT d.*
FROM documents d
INNER JOIN documentLabels dl ON d.id = dl.documentId
WHERE d.folderId = $1 AND dl.label = $2
ORDER BY d.id;
-- name: GetAllLabels :many
SELECT * FROM labels
ORDER BY label;
-- name: CreateLabel :one
INSERT INTO labels (label, description)
VALUES ($1, $2)
RETURNING *;
-- name: GetDocumentLabelHistory :many
SELECT dl.*, d.filename
FROM documentLabels dl
INNER JOIN documents d ON dl.documentId = d.id
WHERE d.clientId = $1
ORDER BY dl.appliedAt DESC
LIMIT $2 OFFSET $3;
+22 -12
View File
@@ -31,7 +31,7 @@ func (q *Queries) AddDocumentEntry(ctx context.Context, arg *AddDocumentEntryPar
}
const addDocumentUpload = `-- name: AddDocumentUpload :exec
INSERT INTO documentUploads (id, clientId, bucket, key, part, createdAt, filename, batch_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
INSERT INTO documentUploads (id, clientId, bucket, key, part, createdAt, filename, batch_id, folder_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
`
type AddDocumentUploadParams struct {
@@ -43,11 +43,12 @@ type AddDocumentUploadParams struct {
Createdat pgtype.Timestamp `db:"createdat"`
Filename *string `db:"filename"`
BatchID *uuid.UUID `db:"batch_id"`
FolderID *uuid.UUID `db:"folder_id"`
}
// AddDocumentUpload
//
// INSERT INTO documentUploads (id, clientId, bucket, key, part, createdAt, filename, batch_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
// INSERT INTO documentUploads (id, clientId, bucket, key, part, createdAt, filename, batch_id, folder_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
func (q *Queries) AddDocumentUpload(ctx context.Context, arg *AddDocumentUploadParams) error {
_, err := q.db.Exec(ctx, addDocumentUpload,
arg.ID,
@@ -58,30 +59,35 @@ func (q *Queries) AddDocumentUpload(ctx context.Context, arg *AddDocumentUploadP
arg.Createdat,
arg.Filename,
arg.BatchID,
arg.FolderID,
)
return err
}
const createDocument = `-- name: CreateDocument :one
INSERT INTO documents (clientId, hash, batch_id, filename) VALUES ($1, $2, $3, $4) RETURNING id
INSERT INTO documents (clientId, hash, batch_id, filename, folderId, originalPath) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id
`
type CreateDocumentParams struct {
Clientid string `db:"clientid"`
Hash string `db:"hash"`
BatchID *uuid.UUID `db:"batch_id"`
Filename *string `db:"filename"`
Clientid string `db:"clientid"`
Hash string `db:"hash"`
BatchID *uuid.UUID `db:"batch_id"`
Filename *string `db:"filename"`
Folderid *uuid.UUID `db:"folderid"`
Originalpath *string `db:"originalpath"`
}
// CreateDocument
//
// INSERT INTO documents (clientId, hash, batch_id, filename) VALUES ($1, $2, $3, $4) RETURNING id
// INSERT INTO documents (clientId, hash, batch_id, filename, folderId, originalPath) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id
func (q *Queries) CreateDocument(ctx context.Context, arg *CreateDocumentParams) (uuid.UUID, error) {
row := q.db.QueryRow(ctx, createDocument,
arg.Clientid,
arg.Hash,
arg.BatchID,
arg.Filename,
arg.Folderid,
arg.Originalpath,
)
var id uuid.UUID
err := row.Scan(&id)
@@ -220,7 +226,7 @@ func (q *Queries) GetDocumentSummary(ctx context.Context, id uuid.UUID) (*GetDoc
}
const getDocumentUploadByKey = `-- name: GetDocumentUploadByKey :one
SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id FROM documentUploads WHERE bucket = $1 AND key = $2 LIMIT 1
SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id, folder_id FROM documentUploads WHERE bucket = $1 AND key = $2 LIMIT 1
`
type GetDocumentUploadByKeyParams struct {
@@ -237,11 +243,12 @@ type GetDocumentUploadByKeyRow struct {
Createdat pgtype.Timestamp `db:"createdat"`
Filename *string `db:"filename"`
BatchID *uuid.UUID `db:"batch_id"`
FolderID *uuid.UUID `db:"folder_id"`
}
// GetDocumentUploadByKey
//
// SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id FROM documentUploads WHERE bucket = $1 AND key = $2 LIMIT 1
// SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id, folder_id FROM documentUploads WHERE bucket = $1 AND key = $2 LIMIT 1
func (q *Queries) GetDocumentUploadByKey(ctx context.Context, arg *GetDocumentUploadByKeyParams) (*GetDocumentUploadByKeyRow, error) {
row := q.db.QueryRow(ctx, getDocumentUploadByKey, arg.Bucket, arg.Key)
var i GetDocumentUploadByKeyRow
@@ -254,6 +261,7 @@ func (q *Queries) GetDocumentUploadByKey(ctx context.Context, arg *GetDocumentUp
&i.Createdat,
&i.Filename,
&i.BatchID,
&i.FolderID,
)
return &i, err
}
@@ -355,7 +363,7 @@ func (q *Queries) ListDocumentIDsBatch(ctx context.Context, arg *ListDocumentIDs
}
const listDocumentUploads = `-- name: ListDocumentUploads :many
SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id FROM documentUploads WHERE clientId = $1 ORDER BY createdAt
SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id, folder_id FROM documentUploads WHERE clientId = $1 ORDER BY createdAt
`
type ListDocumentUploadsRow struct {
@@ -367,11 +375,12 @@ type ListDocumentUploadsRow struct {
Createdat pgtype.Timestamp `db:"createdat"`
Filename *string `db:"filename"`
BatchID *uuid.UUID `db:"batch_id"`
FolderID *uuid.UUID `db:"folder_id"`
}
// ListDocumentUploads
//
// SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id FROM documentUploads WHERE clientId = $1 ORDER BY createdAt
// SELECT id, clientId, bucket, key, part, createdAt, filename, batch_id, folder_id FROM documentUploads WHERE clientId = $1 ORDER BY createdAt
func (q *Queries) ListDocumentUploads(ctx context.Context, clientid string) ([]*ListDocumentUploadsRow, error) {
rows, err := q.db.Query(ctx, listDocumentUploads, clientid)
if err != nil {
@@ -390,6 +399,7 @@ func (q *Queries) ListDocumentUploads(ctx context.Context, clientid string) ([]*
&i.Createdat,
&i.Filename,
&i.BatchID,
&i.FolderID,
); err != nil {
return nil, err
}
File diff suppressed because it is too large Load Diff
+510
View File
@@ -0,0 +1,510 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: folders.sql
package repository
import (
"context"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
)
const countDocumentsByFolder = `-- name: CountDocumentsByFolder :one
SELECT COUNT(*) as total FROM documents
WHERE folderId = $1
`
// CountDocumentsByFolder
//
// SELECT COUNT(*) as total FROM documents
// WHERE folderId = $1
func (q *Queries) CountDocumentsByFolder(ctx context.Context, folderid *uuid.UUID) (int64, error) {
row := q.db.QueryRow(ctx, countDocumentsByFolder, folderid)
var total int64
err := row.Scan(&total)
return total, err
}
const createFolder = `-- name: CreateFolder :one
INSERT INTO folders (path, parentId, clientId, createdBy)
VALUES ($1, $2, $3, $4)
RETURNING id, path, parentid, clientid, createdat, createdby
`
type CreateFolderParams struct {
Path string `db:"path"`
Parentid *uuid.UUID `db:"parentid"`
Clientid string `db:"clientid"`
Createdby string `db:"createdby"`
}
// CreateFolder
//
// INSERT INTO folders (path, parentId, clientId, createdBy)
// VALUES ($1, $2, $3, $4)
// RETURNING id, path, parentid, clientid, createdat, createdby
func (q *Queries) CreateFolder(ctx context.Context, arg *CreateFolderParams) (*Folder, error) {
row := q.db.QueryRow(ctx, createFolder,
arg.Path,
arg.Parentid,
arg.Clientid,
arg.Createdby,
)
var i Folder
err := row.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
)
return &i, err
}
const getClientRootFolder = `-- name: GetClientRootFolder :one
SELECT id, path, parentid, clientid, createdat, createdby FROM folders
WHERE clientId = $1 AND path = '/'
`
// Returns the root folder "/" for a client
//
// SELECT id, path, parentid, clientid, createdat, createdby FROM folders
// WHERE clientId = $1 AND path = '/'
func (q *Queries) GetClientRootFolder(ctx context.Context, clientid string) (*Folder, error) {
row := q.db.QueryRow(ctx, getClientRootFolder, clientid)
var i Folder
err := row.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
)
return &i, err
}
const getDocumentsByFolder = `-- name: GetDocumentsByFolder :many
SELECT id, clientid, hash, batch_id, filename, folderid, originalpath FROM documents
WHERE folderId = $1
ORDER BY id
`
// GetDocumentsByFolder
//
// SELECT id, clientid, hash, batch_id, filename, folderid, originalpath FROM documents
// WHERE folderId = $1
// ORDER BY id
func (q *Queries) GetDocumentsByFolder(ctx context.Context, folderid *uuid.UUID) ([]*Document, error) {
rows, err := q.db.Query(ctx, getDocumentsByFolder, folderid)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*Document{}
for rows.Next() {
var i Document
if err := rows.Scan(
&i.ID,
&i.Clientid,
&i.Hash,
&i.BatchID,
&i.Filename,
&i.Folderid,
&i.Originalpath,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFolderByID = `-- name: GetFolderByID :one
SELECT id, path, parentid, clientid, createdat, createdby FROM folders
WHERE id = $1
`
// GetFolderByID
//
// SELECT id, path, parentid, clientid, createdat, createdby FROM folders
// WHERE id = $1
func (q *Queries) GetFolderByID(ctx context.Context, id uuid.UUID) (*Folder, error) {
row := q.db.QueryRow(ctx, getFolderByID, id)
var i Folder
err := row.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
)
return &i, err
}
const getFolderByPath = `-- name: GetFolderByPath :one
SELECT id, path, parentid, clientid, createdat, createdby FROM folders
WHERE clientId = $1 AND path = $2
`
type GetFolderByPathParams struct {
Clientid string `db:"clientid"`
Path string `db:"path"`
}
// GetFolderByPath
//
// SELECT id, path, parentid, clientid, createdat, createdby FROM folders
// WHERE clientId = $1 AND path = $2
func (q *Queries) GetFolderByPath(ctx context.Context, arg *GetFolderByPathParams) (*Folder, error) {
row := q.db.QueryRow(ctx, getFolderByPath, arg.Clientid, arg.Path)
var i Folder
err := row.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
)
return &i, err
}
const getFolderLabelCounts = `-- name: GetFolderLabelCounts :many
SELECT dl.label, COUNT(DISTINCT dl.documentId) as count
FROM documents d
INNER JOIN documentLabels dl ON d.id = dl.documentId
WHERE d.folderId = $1
GROUP BY dl.label
ORDER BY dl.label
`
type GetFolderLabelCountsRow struct {
Label string `db:"label"`
Count int64 `db:"count"`
}
// GetFolderLabelCounts
//
// SELECT dl.label, COUNT(DISTINCT dl.documentId) as count
// FROM documents d
// INNER JOIN documentLabels dl ON d.id = dl.documentId
// WHERE d.folderId = $1
// GROUP BY dl.label
// ORDER BY dl.label
func (q *Queries) GetFolderLabelCounts(ctx context.Context, folderid *uuid.UUID) ([]*GetFolderLabelCountsRow, error) {
rows, err := q.db.Query(ctx, getFolderLabelCounts, folderid)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*GetFolderLabelCountsRow{}
for rows.Next() {
var i GetFolderLabelCountsRow
if err := rows.Scan(&i.Label, &i.Count); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFolderTree = `-- name: GetFolderTree :many
WITH RECURSIVE folder_tree AS (
-- Base case: start with the target folder
SELECT id, path, parentId, clientId, createdAt, createdBy
FROM folders
WHERE id = $1
UNION ALL
-- Recursive case: find all child folders
SELECT f.id, f.path, f.parentId, f.clientId, f.createdAt, f.createdBy
FROM folders f
INNER JOIN folder_tree ft ON f.parentId = ft.id
)
SELECT id, path, parentId, clientId, createdAt, createdBy
FROM folder_tree
ORDER BY path
`
type GetFolderTreeRow struct {
ID uuid.UUID `db:"id"`
Path string `db:"path"`
Parentid *uuid.UUID `db:"parentid"`
Clientid string `db:"clientid"`
Createdat pgtype.Timestamp `db:"createdat"`
Createdby string `db:"createdby"`
}
// GetFolderTree
//
// WITH RECURSIVE folder_tree AS (
// -- Base case: start with the target folder
// SELECT id, path, parentId, clientId, createdAt, createdBy
// FROM folders
// WHERE id = $1
//
// UNION ALL
//
// -- Recursive case: find all child folders
// SELECT f.id, f.path, f.parentId, f.clientId, f.createdAt, f.createdBy
// FROM folders f
// INNER JOIN folder_tree ft ON f.parentId = ft.id
// )
// SELECT id, path, parentId, clientId, createdAt, createdBy
// FROM folder_tree
// ORDER BY path
func (q *Queries) GetFolderTree(ctx context.Context, dollar_1 *uuid.UUID) ([]*GetFolderTreeRow, error) {
rows, err := q.db.Query(ctx, getFolderTree, dollar_1)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*GetFolderTreeRow{}
for rows.Next() {
var i GetFolderTreeRow
if err := rows.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFoldersByClientID = `-- name: GetFoldersByClientID :many
SELECT id, path, parentid, clientid, createdat, createdby FROM folders
WHERE clientId = $1
ORDER BY path
`
// GetFoldersByClientID
//
// SELECT id, path, parentid, clientid, createdat, createdby FROM folders
// WHERE clientId = $1
// ORDER BY path
func (q *Queries) GetFoldersByClientID(ctx context.Context, clientid string) ([]*Folder, error) {
rows, err := q.db.Query(ctx, getFoldersByClientID, clientid)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*Folder{}
for rows.Next() {
var i Folder
if err := rows.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getFoldersByParentID = `-- name: GetFoldersByParentID :many
SELECT id, path, parentid, clientid, createdat, createdby FROM folders
WHERE parentId = $1
ORDER BY path
`
// GetFoldersByParentID
//
// SELECT id, path, parentid, clientid, createdat, createdby FROM folders
// WHERE parentId = $1
// ORDER BY path
func (q *Queries) GetFoldersByParentID(ctx context.Context, parentid *uuid.UUID) ([]*Folder, error) {
rows, err := q.db.Query(ctx, getFoldersByParentID, parentid)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*Folder{}
for rows.Next() {
var i Folder
if err := rows.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getRootFolders = `-- name: GetRootFolders :many
SELECT id, path, parentid, clientid, createdat, createdby FROM folders
WHERE clientId = $1 AND parentId IS NULL
ORDER BY path
`
// Returns folders with null parentId (should only be the "/" root folder for each client)
//
// SELECT id, path, parentid, clientid, createdat, createdby FROM folders
// WHERE clientId = $1 AND parentId IS NULL
// ORDER BY path
func (q *Queries) GetRootFolders(ctx context.Context, clientid string) ([]*Folder, error) {
rows, err := q.db.Query(ctx, getRootFolders, clientid)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*Folder{}
for rows.Next() {
var i Folder
if err := rows.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTopLevelFolders = `-- name: GetTopLevelFolders :many
SELECT f.id, f.path, f.parentid, f.clientid, f.createdat, f.createdby FROM folders f
INNER JOIN folders root ON f.parentId = root.id
WHERE f.clientId = $1 AND root.path = '/'
ORDER BY f.path
`
// Returns folders that are direct children of the root folder "/"
// These are the user-visible top-level folders (e.g., /folder1, /folder2)
//
// SELECT f.id, f.path, f.parentid, f.clientid, f.createdat, f.createdby FROM folders f
// INNER JOIN folders root ON f.parentId = root.id
// WHERE f.clientId = $1 AND root.path = '/'
// ORDER BY f.path
func (q *Queries) GetTopLevelFolders(ctx context.Context, clientid string) ([]*Folder, error) {
rows, err := q.db.Query(ctx, getTopLevelFolders, clientid)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*Folder{}
for rows.Next() {
var i Folder
if err := rows.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const renameFolder = `-- name: RenameFolder :exec
UPDATE folders
SET path = $2
WHERE id = $1
`
type RenameFolderParams struct {
ID uuid.UUID `db:"id"`
Path string `db:"path"`
}
// RenameFolder
//
// UPDATE folders
// SET path = $2
// WHERE id = $1
func (q *Queries) RenameFolder(ctx context.Context, arg *RenameFolderParams) error {
_, err := q.db.Exec(ctx, renameFolder, arg.ID, arg.Path)
return err
}
const upsertFolder = `-- name: UpsertFolder :one
INSERT INTO folders (path, parentId, clientId, createdBy)
VALUES ($1, $2, $3, $4)
ON CONFLICT (clientId, path) DO UPDATE SET path = EXCLUDED.path
RETURNING id, path, parentid, clientid, createdat, createdby
`
type UpsertFolderParams struct {
Path string `db:"path"`
Parentid *uuid.UUID `db:"parentid"`
Clientid string `db:"clientid"`
Createdby string `db:"createdby"`
}
// Insert a folder if it doesn't exist, or return the existing one
// Used for auto-creating folder hierarchies during document upload
//
// INSERT INTO folders (path, parentId, clientId, createdBy)
// VALUES ($1, $2, $3, $4)
// ON CONFLICT (clientId, path) DO UPDATE SET path = EXCLUDED.path
// RETURNING id, path, parentid, clientid, createdat, createdby
func (q *Queries) UpsertFolder(ctx context.Context, arg *UpsertFolderParams) (*Folder, error) {
row := q.db.QueryRow(ctx, upsertFolder,
arg.Path,
arg.Parentid,
arg.Clientid,
arg.Createdby,
)
var i Folder
err := row.Scan(
&i.ID,
&i.Path,
&i.Parentid,
&i.Clientid,
&i.Createdat,
&i.Createdby,
)
return &i, err
}
+318
View File
@@ -0,0 +1,318 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: labels.sql
package repository
import (
"context"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
)
const applyLabel = `-- name: ApplyLabel :one
INSERT INTO documentLabels (documentId, label, appliedBy)
VALUES ($1, $2, $3)
RETURNING id, documentid, label, appliedat, appliedby
`
type ApplyLabelParams struct {
Documentid uuid.UUID `db:"documentid"`
Label string `db:"label"`
Appliedby string `db:"appliedby"`
}
// ApplyLabel
//
// INSERT INTO documentLabels (documentId, label, appliedBy)
// VALUES ($1, $2, $3)
// RETURNING id, documentid, label, appliedat, appliedby
func (q *Queries) ApplyLabel(ctx context.Context, arg *ApplyLabelParams) (*Documentlabel, error) {
row := q.db.QueryRow(ctx, applyLabel, arg.Documentid, arg.Label, arg.Appliedby)
var i Documentlabel
err := row.Scan(
&i.ID,
&i.Documentid,
&i.Label,
&i.Appliedat,
&i.Appliedby,
)
return &i, err
}
const createLabel = `-- name: CreateLabel :one
INSERT INTO labels (label, description)
VALUES ($1, $2)
RETURNING label, description
`
type CreateLabelParams struct {
Label string `db:"label"`
Description string `db:"description"`
}
// CreateLabel
//
// INSERT INTO labels (label, description)
// VALUES ($1, $2)
// RETURNING label, description
func (q *Queries) CreateLabel(ctx context.Context, arg *CreateLabelParams) (*Label, error) {
row := q.db.QueryRow(ctx, createLabel, arg.Label, arg.Description)
var i Label
err := row.Scan(&i.Label, &i.Description)
return &i, err
}
const getAllLabels = `-- name: GetAllLabels :many
SELECT label, description FROM labels
ORDER BY label
`
// GetAllLabels
//
// SELECT label, description FROM labels
// ORDER BY label
func (q *Queries) GetAllLabels(ctx context.Context) ([]*Label, error) {
rows, err := q.db.Query(ctx, getAllLabels)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*Label{}
for rows.Next() {
var i Label
if err := rows.Scan(&i.Label, &i.Description); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getDocumentLabelHistory = `-- name: GetDocumentLabelHistory :many
SELECT dl.id, dl.documentid, dl.label, dl.appliedat, dl.appliedby, d.filename
FROM documentLabels dl
INNER JOIN documents d ON dl.documentId = d.id
WHERE d.clientId = $1
ORDER BY dl.appliedAt DESC
LIMIT $2 OFFSET $3
`
type GetDocumentLabelHistoryParams struct {
Clientid string `db:"clientid"`
Limit int64 `db:"limit"`
Offset int64 `db:"offset"`
}
type GetDocumentLabelHistoryRow struct {
ID uuid.UUID `db:"id"`
Documentid uuid.UUID `db:"documentid"`
Label string `db:"label"`
Appliedat pgtype.Timestamp `db:"appliedat"`
Appliedby string `db:"appliedby"`
Filename *string `db:"filename"`
}
// GetDocumentLabelHistory
//
// SELECT dl.id, dl.documentid, dl.label, dl.appliedat, dl.appliedby, d.filename
// FROM documentLabels dl
// INNER JOIN documents d ON dl.documentId = d.id
// WHERE d.clientId = $1
// ORDER BY dl.appliedAt DESC
// LIMIT $2 OFFSET $3
func (q *Queries) GetDocumentLabelHistory(ctx context.Context, arg *GetDocumentLabelHistoryParams) ([]*GetDocumentLabelHistoryRow, error) {
rows, err := q.db.Query(ctx, getDocumentLabelHistory, arg.Clientid, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*GetDocumentLabelHistoryRow{}
for rows.Next() {
var i GetDocumentLabelHistoryRow
if err := rows.Scan(
&i.ID,
&i.Documentid,
&i.Label,
&i.Appliedat,
&i.Appliedby,
&i.Filename,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getDocumentLabels = `-- name: GetDocumentLabels :many
SELECT id, documentid, label, appliedat, appliedby FROM documentLabels
WHERE documentId = $1
ORDER BY appliedAt DESC
`
// GetDocumentLabels
//
// SELECT id, documentid, label, appliedat, appliedby FROM documentLabels
// WHERE documentId = $1
// ORDER BY appliedAt DESC
func (q *Queries) GetDocumentLabels(ctx context.Context, documentid uuid.UUID) ([]*Documentlabel, error) {
rows, err := q.db.Query(ctx, getDocumentLabels, documentid)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*Documentlabel{}
for rows.Next() {
var i Documentlabel
if err := rows.Scan(
&i.ID,
&i.Documentid,
&i.Label,
&i.Appliedat,
&i.Appliedby,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getDocumentsByLabel = `-- name: GetDocumentsByLabel :many
SELECT DISTINCT d.id, d.clientid, d.hash, d.batch_id, d.filename, d.folderid, d.originalpath
FROM documents d
INNER JOIN documentLabels dl ON d.id = dl.documentId
WHERE d.clientId = $1 AND dl.label = $2
ORDER BY d.id
`
type GetDocumentsByLabelParams struct {
Clientid string `db:"clientid"`
Label string `db:"label"`
}
// GetDocumentsByLabel
//
// SELECT DISTINCT d.id, d.clientid, d.hash, d.batch_id, d.filename, d.folderid, d.originalpath
// FROM documents d
// INNER JOIN documentLabels dl ON d.id = dl.documentId
// WHERE d.clientId = $1 AND dl.label = $2
// ORDER BY d.id
func (q *Queries) GetDocumentsByLabel(ctx context.Context, arg *GetDocumentsByLabelParams) ([]*Document, error) {
rows, err := q.db.Query(ctx, getDocumentsByLabel, arg.Clientid, arg.Label)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*Document{}
for rows.Next() {
var i Document
if err := rows.Scan(
&i.ID,
&i.Clientid,
&i.Hash,
&i.BatchID,
&i.Filename,
&i.Folderid,
&i.Originalpath,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getDocumentsByLabelAndFolder = `-- name: GetDocumentsByLabelAndFolder :many
SELECT DISTINCT d.id, d.clientid, d.hash, d.batch_id, d.filename, d.folderid, d.originalpath
FROM documents d
INNER JOIN documentLabels dl ON d.id = dl.documentId
WHERE d.folderId = $1 AND dl.label = $2
ORDER BY d.id
`
type GetDocumentsByLabelAndFolderParams struct {
Folderid *uuid.UUID `db:"folderid"`
Label string `db:"label"`
}
// GetDocumentsByLabelAndFolder
//
// SELECT DISTINCT d.id, d.clientid, d.hash, d.batch_id, d.filename, d.folderid, d.originalpath
// FROM documents d
// INNER JOIN documentLabels dl ON d.id = dl.documentId
// WHERE d.folderId = $1 AND dl.label = $2
// ORDER BY d.id
func (q *Queries) GetDocumentsByLabelAndFolder(ctx context.Context, arg *GetDocumentsByLabelAndFolderParams) ([]*Document, error) {
rows, err := q.db.Query(ctx, getDocumentsByLabelAndFolder, arg.Folderid, arg.Label)
if err != nil {
return nil, err
}
defer rows.Close()
items := []*Document{}
for rows.Next() {
var i Document
if err := rows.Scan(
&i.ID,
&i.Clientid,
&i.Hash,
&i.BatchID,
&i.Filename,
&i.Folderid,
&i.Originalpath,
); err != nil {
return nil, err
}
items = append(items, &i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getMostRecentLabel = `-- name: GetMostRecentLabel :one
SELECT id, documentid, label, appliedat, appliedby FROM documentLabels
WHERE documentId = $1 AND label = $2
ORDER BY appliedAt DESC
LIMIT 1
`
type GetMostRecentLabelParams struct {
Documentid uuid.UUID `db:"documentid"`
Label string `db:"label"`
}
// GetMostRecentLabel
//
// SELECT id, documentid, label, appliedat, appliedby FROM documentLabels
// WHERE documentId = $1 AND label = $2
// ORDER BY appliedAt DESC
// LIMIT 1
func (q *Queries) GetMostRecentLabel(ctx context.Context, arg *GetMostRecentLabelParams) (*Documentlabel, error) {
row := q.db.QueryRow(ctx, getMostRecentLabel, arg.Documentid, arg.Label)
var i Documentlabel
err := row.Scan(
&i.ID,
&i.Documentid,
&i.Label,
&i.Appliedat,
&i.Appliedby,
)
return &i, err
}
+236 -2
View File
@@ -354,6 +354,59 @@ type Currentcollectorquery struct {
Queryid *uuid.UUID `db:"queryid"`
}
type Currentfieldextraction struct {
ID uuid.UUID `db:"id"`
Documentid uuid.UUID `db:"documentid"`
Filename *string `db:"filename"`
Contracttitle *string `db:"contracttitle"`
Aaretederivedamendmentnum *int32 `db:"aaretederivedamendmentnum"`
Clientname *string `db:"clientname"`
Payername *string `db:"payername"`
Payerstate *string `db:"payerstate"`
Providerstate *string `db:"providerstate"`
Filenametin *string `db:"filenametin"`
Provgrouptin *string `db:"provgrouptin"`
Provgroupnpi *string `db:"provgroupnpi"`
Provgroupnamefull *string `db:"provgroupnamefull"`
Provothertin *string `db:"provothertin"`
Provothernpi *string `db:"provothernpi"`
Provothernamefull *string `db:"provothernamefull"`
Aaretederivedeffectivedt pgtype.Date `db:"aaretederivedeffectivedt"`
Aaretederivedterminationdt pgtype.Date `db:"aaretederivedterminationdt"`
Autorenewalind *bool `db:"autorenewalind"`
Autorenewalterm *string `db:"autorenewalterm"`
Version int64 `db:"version"`
Createdby string `db:"createdby"`
Createdat pgtype.Timestamp `db:"createdat"`
}
type Currentfieldextractionswitharraycount struct {
ID uuid.UUID `db:"id"`
Documentid uuid.UUID `db:"documentid"`
Filename *string `db:"filename"`
Contracttitle *string `db:"contracttitle"`
Aaretederivedamendmentnum *int32 `db:"aaretederivedamendmentnum"`
Clientname *string `db:"clientname"`
Payername *string `db:"payername"`
Payerstate *string `db:"payerstate"`
Providerstate *string `db:"providerstate"`
Filenametin *string `db:"filenametin"`
Provgrouptin *string `db:"provgrouptin"`
Provgroupnpi *string `db:"provgroupnpi"`
Provgroupnamefull *string `db:"provgroupnamefull"`
Provothertin *string `db:"provothertin"`
Provothernpi *string `db:"provothernpi"`
Provothernamefull *string `db:"provothernamefull"`
Aaretederivedeffectivedt pgtype.Date `db:"aaretederivedeffectivedt"`
Aaretederivedterminationdt pgtype.Date `db:"aaretederivedterminationdt"`
Autorenewalind *bool `db:"autorenewalind"`
Autorenewalterm *string `db:"autorenewalterm"`
Version int64 `db:"version"`
Createdby string `db:"createdby"`
Createdat pgtype.Timestamp `db:"createdat"`
Arraysize int64 `db:"arraysize"`
}
type Currenttextentry struct {
ID uuid.UUID `db:"id"`
Documentid uuid.UUID `db:"documentid"`
@@ -370,6 +423,9 @@ type Document struct {
Hash string `db:"hash"`
BatchID *uuid.UUID `db:"batch_id"`
Filename *string `db:"filename"`
Folderid *uuid.UUID `db:"folderid"`
// Original path provided during upload. IMMUTABLE after creation - never modify this value.
Originalpath *string `db:"originalpath"`
}
type Documentclean struct {
@@ -391,8 +447,169 @@ type Documentcleanentry struct {
type Documententry struct {
ID uuid.UUID `db:"id"`
Documentid uuid.UUID `db:"documentid"`
Bucket string `db:"bucket"`
Key string `db:"key"`
// S3 bucket name. IMMUTABLE after creation - never modify this value.
Bucket string `db:"bucket"`
// S3 object key. IMMUTABLE after creation - never modify this value.
Key string `db:"key"`
}
type Documentfieldextraction struct {
ID uuid.UUID `db:"id"`
Documentid uuid.UUID `db:"documentid"`
Filename *string `db:"filename"`
Contracttitle *string `db:"contracttitle"`
Aaretederivedamendmentnum *int32 `db:"aaretederivedamendmentnum"`
Clientname *string `db:"clientname"`
Payername *string `db:"payername"`
Payerstate *string `db:"payerstate"`
Providerstate *string `db:"providerstate"`
Filenametin *string `db:"filenametin"`
Provgrouptin *string `db:"provgrouptin"`
Provgroupnpi *string `db:"provgroupnpi"`
Provgroupnamefull *string `db:"provgroupnamefull"`
Provothertin *string `db:"provothertin"`
Provothernpi *string `db:"provothernpi"`
Provothernamefull *string `db:"provothernamefull"`
Aaretederivedeffectivedt pgtype.Date `db:"aaretederivedeffectivedt"`
Aaretederivedterminationdt pgtype.Date `db:"aaretederivedterminationdt"`
Autorenewalind *bool `db:"autorenewalind"`
Autorenewalterm *string `db:"autorenewalterm"`
Createdat pgtype.Timestamp `db:"createdat"`
Createdby string `db:"createdby"`
}
type Documentfieldextractionarrayfield struct {
ID uuid.UUID `db:"id"`
Fieldextractionid uuid.UUID `db:"fieldextractionid"`
Arrayindex int16 `db:"arrayindex"`
Exhibittitle *string `db:"exhibittitle"`
Exhibitpage *string `db:"exhibitpage"`
Reimbprovtin *string `db:"reimbprovtin"`
Reimbprovnpi *string `db:"reimbprovnpi"`
Reimbprovname *string `db:"reimbprovname"`
Reimbeffectivedt pgtype.Date `db:"reimbeffectivedt"`
Reimbterminationdt pgtype.Date `db:"reimbterminationdt"`
Aaretederivedclaimtypecd *string `db:"aaretederivedclaimtypecd"`
Aaretederivedproduct *string `db:"aaretederivedproduct"`
Aaretederivedlob *string `db:"aaretederivedlob"`
Aaretederivedprogram *string `db:"aaretederivedprogram"`
Aaretederivednetwork *string `db:"aaretederivednetwork"`
Aaretederivedprovtype *string `db:"aaretederivedprovtype"`
Provtaxonomycd *string `db:"provtaxonomycd"`
Provtaxonomycddesc *string `db:"provtaxonomycddesc"`
Provspecialtycd *string `db:"provspecialtycd"`
Provspecialtycddesc *string `db:"provspecialtycddesc"`
Placeofservicecd *string `db:"placeofservicecd"`
Placeofservicecddesc *string `db:"placeofservicecddesc"`
Billtypecd *string `db:"billtypecd"`
Billtypecddesc *string `db:"billtypecddesc"`
Patientagemin *string `db:"patientagemin"`
Patientagemax *string `db:"patientagemax"`
Reimbterm *string `db:"reimbterm"`
Lobprogramrelationship *string `db:"lobprogramrelationship"`
Lobproductrelationship *string `db:"lobproductrelationship"`
Carveoutind *bool `db:"carveoutind"`
Carveoutcd *string `db:"carveoutcd"`
Lesserofind *bool `db:"lesserofind"`
Greaterofind *bool `db:"greaterofind"`
Aaretederivedreimbmethod *string `db:"aaretederivedreimbmethod"`
Unitofmeasure *string `db:"unitofmeasure"`
Reimbpctrate pgtype.Numeric `db:"reimbpctrate"`
Reimbfeerate pgtype.Numeric `db:"reimbfeerate"`
Reimbconversionfactor pgtype.Numeric `db:"reimbconversionfactor"`
Triggercapthresholdamt pgtype.Numeric `db:"triggercapthresholdamt"`
Triggerbasethreshold pgtype.Numeric `db:"triggerbasethreshold"`
Defaultind *bool `db:"defaultind"`
Additiondesc *string `db:"additiondesc"`
Additionmaxfeerateinc pgtype.Numeric `db:"additionmaxfeerateinc"`
Additionmaxpctrateinc pgtype.Numeric `db:"additionmaxpctrateinc"`
Aaretederivedadditionratechangetimeline *string `db:"aaretederivedadditionratechangetimeline"`
Aaretederivedfeeschedule *string `db:"aaretederivedfeeschedule"`
Aaretederivedfeescheduleversion *string `db:"aaretederivedfeescheduleversion"`
Serviceterm *string `db:"serviceterm"`
Cpt4proccd *string `db:"cpt4proccd"`
Cpt4proccddesc *string `db:"cpt4proccddesc"`
Cpt4procmod *string `db:"cpt4procmod"`
Cpt4procmoddesc *string `db:"cpt4procmoddesc"`
Revenuecd *string `db:"revenuecd"`
Revenuecddesc *string `db:"revenuecddesc"`
Diagcd *string `db:"diagcd"`
Diagcddesc *string `db:"diagcddesc"`
Ndccd *string `db:"ndccd"`
Ndccddesc *string `db:"ndccddesc"`
Claimadmittypecd *string `db:"claimadmittypecd"`
Authadmittypedesc *string `db:"authadmittypedesc"`
Claimstatuscd *string `db:"claimstatuscd"`
Claimstatuscddesc *string `db:"claimstatuscddesc"`
Groupertype *string `db:"groupertype"`
Groupercd *string `db:"groupercd"`
Groupercddesc *string `db:"groupercddesc"`
Grouperpctrate pgtype.Numeric `db:"grouperpctrate"`
Grouperbaserate pgtype.Numeric `db:"grouperbaserate"`
Aaretederivedgrouperversion *string `db:"aaretederivedgrouperversion"`
Grouperalternativelevelofcare *string `db:"grouperalternativelevelofcare"`
Grouperseverityind *bool `db:"grouperseverityind"`
Grouperseverity *string `db:"grouperseverity"`
Grouperriskofmortalitysubclass *string `db:"grouperriskofmortalitysubclass"`
Groupertransferind *bool `db:"groupertransferind"`
Grouperreadmissionsind *bool `db:"grouperreadmissionsind"`
Grouperhacind *bool `db:"grouperhacind"`
Outlierterm *string `db:"outlierterm"`
Outlierfirstdollarind *bool `db:"outlierfirstdollarind"`
Rangenbrdays *string `db:"rangenbrdays"`
Outlierfixedlossnbrdaysthreshold pgtype.Numeric `db:"outlierfixedlossnbrdaysthreshold"`
Outlierfixedlossthreshold pgtype.Numeric `db:"outlierfixedlossthreshold"`
Outliermaximum pgtype.Numeric `db:"outliermaximum"`
Outliermaximumfrequency pgtype.Numeric `db:"outliermaximumfrequency"`
Outlierpctrate pgtype.Numeric `db:"outlierpctrate"`
Outlierexclusioncd *string `db:"outlierexclusioncd"`
Outlierexclusioncddesc *string `db:"outlierexclusioncddesc"`
Facilityadjustmentterm *string `db:"facilityadjustmentterm"`
Dshind *bool `db:"dshind"`
Dshpctrate pgtype.Numeric `db:"dshpctrate"`
Dshfeerate pgtype.Numeric `db:"dshfeerate"`
Imeind *bool `db:"imeind"`
Imepctrate pgtype.Numeric `db:"imepctrate"`
Imefeerate pgtype.Numeric `db:"imefeerate"`
Ntapind *bool `db:"ntapind"`
Ntappctrate pgtype.Numeric `db:"ntappctrate"`
Ntapfeerate pgtype.Numeric `db:"ntapfeerate"`
Ucind *bool `db:"ucind"`
Ucpctrate pgtype.Numeric `db:"ucpctrate"`
Ucfeerate pgtype.Numeric `db:"ucfeerate"`
Gmeind *bool `db:"gmeind"`
Gmepctrate pgtype.Numeric `db:"gmepctrate"`
Gmefeerate pgtype.Numeric `db:"gmefeerate"`
Rateescalatorind *bool `db:"rateescalatorind"`
Rateescalatordesc *string `db:"rateescalatordesc"`
Rateescalatormaxrateincpct pgtype.Numeric `db:"rateescalatormaxrateincpct"`
Rateescalatorratechangetimeline pgtype.Numeric `db:"rateescalatorratechangetimeline"`
Stoplossterm *string `db:"stoplossterm"`
Stoplossfirstdollarind *bool `db:"stoplossfirstdollarind"`
Stoplossrangenbrdays pgtype.Numeric `db:"stoplossrangenbrdays"`
Stoplossfixedlossthreshold pgtype.Numeric `db:"stoplossfixedlossthreshold"`
Stoplossmaximum pgtype.Numeric `db:"stoplossmaximum"`
Stoplossmaximumfrequency pgtype.Numeric `db:"stoplossmaximumfrequency"`
Stoplossdailymaxrate pgtype.Numeric `db:"stoplossdailymaxrate"`
Stoplosspctrateonexcesscharges pgtype.Numeric `db:"stoplosspctrateonexcesscharges"`
Stoplossexclusioncd *string `db:"stoplossexclusioncd"`
Stoplossexclusiondesc *string `db:"stoplossexclusiondesc"`
}
type Documentfieldextractionversion struct {
ID uuid.UUID `db:"id"`
Fieldextractionid uuid.UUID `db:"fieldextractionid"`
Version int64 `db:"version"`
Createdby string `db:"createdby"`
Createdat pgtype.Timestamp `db:"createdat"`
}
type Documentlabel struct {
ID uuid.UUID `db:"id"`
Documentid uuid.UUID `db:"documentid"`
Label string `db:"label"`
Appliedat pgtype.Timestamp `db:"appliedat"`
Appliedby string `db:"appliedby"`
}
type Documenttextextraction struct {
@@ -420,6 +637,18 @@ type Documentupload struct {
Createdat pgtype.Timestamp `db:"createdat"`
Filename *string `db:"filename"`
BatchID *uuid.UUID `db:"batch_id"`
FolderID *uuid.UUID `db:"folder_id"`
}
// Virtual folder hierarchy for document organization. Database-only - has no direct relationship to S3 storage locations.
type Folder struct {
ID uuid.UUID `db:"id"`
// Virtual folder path (e.g., "/contracts/2025"). Can be renamed without affecting S3 storage.
Path string `db:"path"`
Parentid *uuid.UUID `db:"parentid"`
Clientid string `db:"clientid"`
Createdat pgtype.Timestamp `db:"createdat"`
Createdby string `db:"createdby"`
}
type Fullactivecollector struct {
@@ -446,6 +675,11 @@ type Fullclient struct {
Cansync bool `db:"cansync"`
}
type Label struct {
Label string `db:"label"`
Description string `db:"description"`
}
type Query struct {
Queryid uuid.UUID `db:"queryid"`
Querytype Querytype `db:"querytype"`