forked from 18F/couch-rules-engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcouchLoader.js
More file actions
172 lines (142 loc) Β· 7.16 KB
/
couchLoader.js
File metadata and controls
172 lines (142 loc) Β· 7.16 KB
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
const fs = require('fs').promises;
const path = require('path');
const config = require('./config').options;
// Dynamic import for node-fetch (ES module)
async function loadValidators() {
const fetch = (await import('node-fetch')).default;
// Create URL to CouchDB instance and DB
let dbName = process.env.DB_NAME || process.argv[2] || 'rules_db';
let url = `${config.couchdb_url}${dbName}`;
console.log(`π Loading validators to: ${url}`);
// Create Basic Auth header
const auth = Buffer.from(`${config.username}:${config.password}`).toString('base64');
try {
// First verify database exists
const dbResponse = await fetch(url, {
method: 'HEAD',
headers: { 'Authorization': `Basic ${auth}` }
});
if (!dbResponse.ok) {
console.log(`β Database '${dbName}' does not exist or is not accessible`);
console.log(` Create it first or check your connection settings`);
process.exit(1);
}
// Scan validators directory for .js files
const validatorsDir = path.join(__dirname, 'validators');
const files = await fs.readdir(validatorsDir);
const validatorFiles = files.filter(file => file.endsWith('.js'));
console.log(`π Found ${validatorFiles.length} validator files: ${validatorFiles.join(', ')}`);
let successCount = 0;
let updateCount = 0;
let errorCount = 0;
// Load each validator file dynamically
for (const file of validatorFiles) {
const filePath = path.join(validatorsDir, file);
const validatorName = path.basename(file, '.js');
try {
// Dynamically require the validator module
delete require.cache[require.resolve(filePath)]; // Clear cache for hot reloading
const validatorModule = require(filePath);
// Check if the module exports a function with the expected name
if (typeof validatorModule[validatorName] !== 'function') {
console.log(`β οΈ Warning: ${file} does not export a function named '${validatorName}' - skipping`);
continue;
}
console.log(`\nοΏ½ Processing validator: ${validatorName}`);
// Check if design document already exists
const docId = `_design/${validatorName}`;
const docUrl = `${url}/${docId}`;
let existingDoc = null;
const checkResponse = await fetch(docUrl, {
method: 'GET',
headers: { 'Authorization': `Basic ${auth}` }
});
if (checkResponse.ok) {
existingDoc = await checkResponse.json();
console.log(` π Found existing document (rev: ${existingDoc._rev})`);
} else if (checkResponse.status === 404) {
console.log(` β¨ Creating new design document`);
} else {
console.log(` β οΈ Could not check existing document: HTTP ${checkResponse.status}`);
}
// Create design document with metadata and validation function
let doc = {};
doc._id = docId;
// Include revision if updating existing document
if (existingDoc && existingDoc._rev) {
doc._rev = existingDoc._rev;
}
doc.validate_doc_update = validatorModule[validatorName].toString();
// Include metadata if available
if (validatorModule.metadata) {
doc.rule_metadata = validatorModule.metadata;
console.log(` β Including metadata for ${validatorName} validator`);
} else {
// Create basic metadata if none provided
doc.rule_metadata = {
name: validatorName.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase()),
description: `Auto-generated from ${file}`,
version: "1.0.0",
author: "system",
tags: ["auto-generated"],
status: "active",
created_date: new Date().toISOString(),
modified_date: new Date().toISOString()
};
console.log(` β οΈ Generated basic metadata for ${validatorName}`);
}
// Always update the modified_date for existing documents
if (existingDoc) {
doc.rule_metadata.modified_date = new Date().toISOString();
}
// Insert or update the design document
const method = existingDoc ? 'PUT' : 'POST';
const targetUrl = existingDoc ? docUrl : url;
console.log(` π ${existingDoc ? 'Updating' : 'Creating'} design document...`);
const response = await fetch(targetUrl, {
method: method,
headers: {
'Content-Type': 'application/json',
'Authorization': `Basic ${auth}`
},
body: JSON.stringify(doc)
});
if (response.ok) {
const responseData = await response.json();
if (existingDoc) {
console.log(` β
Successfully updated ${validatorName} validator (new rev: ${responseData.rev})`);
updateCount++;
} else {
console.log(` β
Successfully created ${validatorName} validator (rev: ${responseData.rev})`);
successCount++;
}
} else {
const errorData = await response.text();
console.log(` β Failed to ${existingDoc ? 'update' : 'create'} ${validatorName}: HTTP ${response.status} - ${errorData}`);
errorCount++;
}
} catch (moduleError) {
console.log(`β Error loading validator module ${file}: ${moduleError.message}`);
errorCount++;
}
}
// Summary
console.log(`\nπ Validation rule loading completed:`);
console.log(` β
New rules created: ${successCount}`);
console.log(` π Rules updated: ${updateCount}`);
console.log(` β Errors: ${errorCount}`);
console.log(` π Total processed: ${successCount + updateCount + errorCount}`);
if (errorCount > 0) {
process.exit(1);
}
} catch (dirError) {
console.error(`β Error during validator loading: ${dirError.message}`);
process.exit(1);
}
}
// Execute the loader
console.log('π Starting automatic validator discovery and loading...');
loadValidators().catch(error => {
console.error('β Fatal error during validator loading:', error);
process.exit(1);
});