@servicetitan/acquisition-functions 0.12.0 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/filter-fetcher/calc-filter-count.js +51 -65
- package/dist/filter-fetcher/index.js +28 -36
- package/dist/fix-property-use/index.js +43 -42
- package/dist/index.js +16 -29
- package/dist/property-assessorlastsaledate-converter/index.js +45 -41
- package/dist/types.js +1 -2
- package/dist/utils/utils.d.ts +5 -5
- package/dist/utils/utils.js +14 -23
- package/dist/zip-processor.js +20 -22
- package/package.json +2 -2
- package/dist/__tests__/assessorlastsaledate-converter.test.js +0 -79
- package/dist/__tests__/filter-fetcher.test.js +0 -92
- package/dist/__tests__/mock.js +0 -476
- package/dist/__tests__/property-fix-use-group.test.js +0 -63
- package/dist/__tests__/setup.js +0 -39
package/dist/utils/utils.js
CHANGED
|
@@ -1,37 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.capitalizeFirstLetter = capitalizeFirstLetter;
|
|
6
|
-
exports.SEPARATOR_CHARACTER = '___';
|
|
7
|
-
exports.UNKNOWN = 'unknown';
|
|
8
|
-
const isEmptyField = (field) => {
|
|
9
|
-
return field.toLowerCase() === exports.UNKNOWN;
|
|
1
|
+
export const SEPARATOR_CHARACTER = '___';
|
|
2
|
+
export const UNKNOWN = 'unknown';
|
|
3
|
+
export const isEmptyField = (field)=>{
|
|
4
|
+
return field.toLowerCase() === UNKNOWN;
|
|
10
5
|
};
|
|
11
|
-
exports.isEmptyField = isEmptyField;
|
|
12
6
|
const ZIP_STRING_LENGTH = 5;
|
|
13
|
-
const convertToZipString = (zipNumber)
|
|
7
|
+
export const convertToZipString = (zipNumber)=>{
|
|
14
8
|
const zipString = zipNumber + '';
|
|
15
9
|
return zipString.padStart(ZIP_STRING_LENGTH, '0');
|
|
16
10
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
!(0, exports.isEmptyField)(p[propName]))
|
|
23
|
-
.map(p => ({ ...p, [propName]: new Date(p[propName]) }));
|
|
11
|
+
export const convertStringToDate = (props, propName)=>{
|
|
12
|
+
return props.filter((p)=>p[propName] && typeof p[propName] === 'string' && !isEmptyField(p[propName])).map((p)=>({
|
|
13
|
+
...p,
|
|
14
|
+
[propName]: new Date(p[propName])
|
|
15
|
+
}));
|
|
24
16
|
};
|
|
25
|
-
|
|
26
|
-
function FilterNameValidator(filtersToIgnore, unknownCharacter) {
|
|
17
|
+
export function FilterNameValidator(filtersToIgnore, unknownCharacter) {
|
|
27
18
|
return {
|
|
28
|
-
isValidFilterName(filterName, checkIgnoredFilters = true) {
|
|
19
|
+
isValidFilterName (filterName, checkIgnoredFilters = true) {
|
|
29
20
|
const isValidFilter = !checkIgnoredFilters || !filtersToIgnore.includes(filterName);
|
|
30
21
|
return filterName !== unknownCharacter && isValidFilter;
|
|
31
|
-
}
|
|
22
|
+
}
|
|
32
23
|
};
|
|
33
24
|
}
|
|
34
|
-
function capitalizeFirstLetter(val) {
|
|
25
|
+
export function capitalizeFirstLetter(val) {
|
|
35
26
|
if (!val) {
|
|
36
27
|
return val;
|
|
37
28
|
}
|
package/dist/zip-processor.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.zipProcessor = zipProcessor;
|
|
5
|
-
const utils_1 = require("./utils/utils");
|
|
6
|
-
function zipProcessor(workers, processorFn) {
|
|
1
|
+
/* eslint-disable no-await-in-loop, require-atomic-updates */ import { convertToZipString } from './utils/utils';
|
|
2
|
+
export function zipProcessor(workers, processorFn) {
|
|
7
3
|
let processor = null;
|
|
8
4
|
let erroredZips = new Set();
|
|
9
5
|
async function* processZips(zips) {
|
|
@@ -16,24 +12,25 @@ function zipProcessor(workers, processorFn) {
|
|
|
16
12
|
if (!endZipNum) {
|
|
17
13
|
endZipNum = startZipNum;
|
|
18
14
|
}
|
|
19
|
-
for
|
|
15
|
+
for(let zipNum = startZipNum; zipNum <= endZipNum;){
|
|
20
16
|
const processes = [];
|
|
21
17
|
const processZipEnd = zipNum + workers - 1;
|
|
22
|
-
for
|
|
23
|
-
const zip =
|
|
18
|
+
for(; zipNum <= endZipNum && zipNum <= processZipEnd; zipNum++){
|
|
19
|
+
const zip = convertToZipString(zipNum);
|
|
24
20
|
processes.push(processorFn(zip, erroredZips));
|
|
25
21
|
}
|
|
26
22
|
yield await Promise.all(processes);
|
|
27
23
|
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const zip = (0, utils_1.convertToZipString)(Number(zips));
|
|
24
|
+
} else {
|
|
25
|
+
const zip = convertToZipString(Number(zips));
|
|
31
26
|
yield await processorFn(zip, erroredZips);
|
|
32
27
|
}
|
|
33
|
-
while
|
|
34
|
-
const connectionErrorZipsInner = [
|
|
28
|
+
while(erroredZips.size){
|
|
29
|
+
const connectionErrorZipsInner = [
|
|
30
|
+
...erroredZips
|
|
31
|
+
];
|
|
35
32
|
erroredZips = new Set();
|
|
36
|
-
for
|
|
33
|
+
for(let i = 0; i <= connectionErrorZipsInner.length; i++){
|
|
37
34
|
const zip = connectionErrorZipsInner[i];
|
|
38
35
|
yield await processorFn(zip, erroredZips);
|
|
39
36
|
}
|
|
@@ -49,13 +46,15 @@ function zipProcessor(workers, processorFn) {
|
|
|
49
46
|
requests: 0,
|
|
50
47
|
properties: 0,
|
|
51
48
|
errors: 0,
|
|
52
|
-
filters: 0
|
|
49
|
+
filters: 0
|
|
53
50
|
};
|
|
54
51
|
function sumMetas(metas) {
|
|
55
52
|
if (!metas) {
|
|
56
53
|
return;
|
|
57
54
|
}
|
|
58
|
-
return (Array.isArray(metas) ? metas : [
|
|
55
|
+
return (Array.isArray(metas) ? metas : [
|
|
56
|
+
metas
|
|
57
|
+
]).forEach((m)=>{
|
|
59
58
|
meta.requests += m.requests;
|
|
60
59
|
meta.properties += m.properties;
|
|
61
60
|
meta.errors += m.errors;
|
|
@@ -68,20 +67,19 @@ function zipProcessor(workers, processorFn) {
|
|
|
68
67
|
processor = processZips(zips);
|
|
69
68
|
try {
|
|
70
69
|
let isDone = false;
|
|
71
|
-
while
|
|
70
|
+
while(processor && !isDone){
|
|
72
71
|
const step = await processor.next();
|
|
73
72
|
sumMetas(step.value);
|
|
74
73
|
isDone = Boolean(step.done);
|
|
75
74
|
}
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
75
|
+
} catch (e) {
|
|
78
76
|
await clear();
|
|
79
77
|
}
|
|
80
78
|
return meta;
|
|
81
79
|
}
|
|
82
80
|
return {
|
|
83
|
-
getProcessor: ()
|
|
81
|
+
getProcessor: ()=>processor,
|
|
84
82
|
start,
|
|
85
|
-
clear
|
|
83
|
+
clear
|
|
86
84
|
};
|
|
87
85
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/acquisition-functions",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.6.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"typings": "./dist/index.d.ts",
|
|
@@ -27,5 +27,5 @@
|
|
|
27
27
|
"cli": {
|
|
28
28
|
"webpack": false
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "9344d7358ab060d66bd15a574bba612e6052b05f"
|
|
31
31
|
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const globals_1 = require("@jest/globals");
|
|
4
|
-
const index_1 = require("../index");
|
|
5
|
-
const setup_1 = require("./setup");
|
|
6
|
-
describe('property-assessorlastsaledate-converter', () => {
|
|
7
|
-
let processor;
|
|
8
|
-
let base;
|
|
9
|
-
let metadata;
|
|
10
|
-
(0, globals_1.beforeAll)(async () => {
|
|
11
|
-
const client = await (0, setup_1.openConnection)();
|
|
12
|
-
base = client.db('test');
|
|
13
|
-
});
|
|
14
|
-
describe('processor', () => {
|
|
15
|
-
(0, globals_1.beforeEach)(async () => {
|
|
16
|
-
await (0, setup_1.setupProperties)(base);
|
|
17
|
-
processor = (0, index_1.configureProcessor)({
|
|
18
|
-
workers: 1,
|
|
19
|
-
mongoDb: base,
|
|
20
|
-
});
|
|
21
|
-
const { assessorLastSaleDateProcessor } = processor;
|
|
22
|
-
metadata = await assessorLastSaleDateProcessor.start('90001');
|
|
23
|
-
});
|
|
24
|
-
(0, globals_1.test)('should convert existing field to date', async () => {
|
|
25
|
-
const result = await base
|
|
26
|
-
.collection('properties')
|
|
27
|
-
.find({
|
|
28
|
-
assessorlastsaledate: {
|
|
29
|
-
$exists: true,
|
|
30
|
-
},
|
|
31
|
-
})
|
|
32
|
-
.toArray();
|
|
33
|
-
(0, globals_1.expect)(result[0].assessorlastsaledate).toBeInstanceOf(Date);
|
|
34
|
-
});
|
|
35
|
-
(0, globals_1.test)('should not touch nulls', async () => {
|
|
36
|
-
const result = await base
|
|
37
|
-
.collection('properties')
|
|
38
|
-
.find({
|
|
39
|
-
assessorlastsaledate: null,
|
|
40
|
-
})
|
|
41
|
-
.toArray();
|
|
42
|
-
(0, globals_1.expect)(result[0].assessorlastsaledate).toBe(null);
|
|
43
|
-
});
|
|
44
|
-
(0, globals_1.test)('should return metadata', async () => {
|
|
45
|
-
(0, globals_1.expect)(metadata.errors).toBe(0);
|
|
46
|
-
(0, globals_1.expect)(metadata.properties).toBe(1);
|
|
47
|
-
(0, globals_1.expect)(metadata.requests).toBe(2);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
describe('aggregate', () => {
|
|
51
|
-
(0, globals_1.beforeEach)(async () => {
|
|
52
|
-
await (0, setup_1.setupProperties)(base);
|
|
53
|
-
await (0, index_1.propertiesAssessorLastSaleDateAggregate)(base);
|
|
54
|
-
});
|
|
55
|
-
(0, globals_1.test)('should convert existing field to date', async () => {
|
|
56
|
-
const result = await base
|
|
57
|
-
.collection('properties')
|
|
58
|
-
.find({
|
|
59
|
-
assessorlastsaledate: {
|
|
60
|
-
$exists: true,
|
|
61
|
-
},
|
|
62
|
-
})
|
|
63
|
-
.toArray();
|
|
64
|
-
(0, globals_1.expect)(result[0].assessorlastsaledate).toBeInstanceOf(Date);
|
|
65
|
-
});
|
|
66
|
-
(0, globals_1.test)('should not touch nulls', async () => {
|
|
67
|
-
const result = await base
|
|
68
|
-
.collection('properties')
|
|
69
|
-
.find({
|
|
70
|
-
assessorlastsaledate: null,
|
|
71
|
-
})
|
|
72
|
-
.toArray();
|
|
73
|
-
(0, globals_1.expect)(result[0].assessorlastsaledate).toBe(null);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
afterAll(async () => {
|
|
77
|
-
await (0, setup_1.closeConnection)();
|
|
78
|
-
});
|
|
79
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const globals_1 = require("@jest/globals");
|
|
4
|
-
const index_1 = require("../index");
|
|
5
|
-
const setup_1 = require("./setup");
|
|
6
|
-
describe('property-assessorlastsaledate-converter', () => {
|
|
7
|
-
let base;
|
|
8
|
-
let metadata;
|
|
9
|
-
(0, globals_1.beforeAll)(async () => {
|
|
10
|
-
const client = await (0, setup_1.openConnection)();
|
|
11
|
-
base = client.db('test');
|
|
12
|
-
await (0, setup_1.setupProperties)(base);
|
|
13
|
-
const { filterFetcher, propertyUseGroupProcessor } = (0, index_1.configureProcessor)({
|
|
14
|
-
workers: 10,
|
|
15
|
-
mongoDb: base,
|
|
16
|
-
});
|
|
17
|
-
await propertyUseGroupProcessor.start(['90001', '90002']);
|
|
18
|
-
metadata = await filterFetcher.start(['90001', '90002']);
|
|
19
|
-
});
|
|
20
|
-
(0, globals_1.test)('should have empty filter for missing zip', async () => {
|
|
21
|
-
const result = await base.collection('filters').findOne({
|
|
22
|
-
zipcode: '90002',
|
|
23
|
-
});
|
|
24
|
-
(0, globals_1.expect)(result).not.toBe(null);
|
|
25
|
-
(0, globals_1.expect)(result?.propertyusegroup.length).toBe(0);
|
|
26
|
-
(0, globals_1.expect)(result?.flooringmaterialprimary.length).toBe(0);
|
|
27
|
-
(0, globals_1.expect)(result?.hvaccoolingdetail.length).toBe(0);
|
|
28
|
-
(0, globals_1.expect)(result?.hvacheatingdetail.length).toBe(0);
|
|
29
|
-
(0, globals_1.expect)(result?.propertyusestandardized.length).toBe(0);
|
|
30
|
-
(0, globals_1.expect)(result?.utilitieswatersource.length).toBe(0);
|
|
31
|
-
(0, globals_1.expect)(result?.utilitiessewageusage.length).toBe(0);
|
|
32
|
-
});
|
|
33
|
-
(0, globals_1.test)('should return metadata', async () => {
|
|
34
|
-
(0, globals_1.expect)(metadata.errors).toBe(0);
|
|
35
|
-
(0, globals_1.expect)(metadata.properties).toBe(2);
|
|
36
|
-
(0, globals_1.expect)(metadata.requests).toBe(6);
|
|
37
|
-
(0, globals_1.expect)(metadata.filters).toBe(2);
|
|
38
|
-
});
|
|
39
|
-
(0, globals_1.test)('should form correct filter', async () => {
|
|
40
|
-
const result = await base.collection('filters').findOne({
|
|
41
|
-
zipcode: '90001',
|
|
42
|
-
});
|
|
43
|
-
(0, globals_1.expect)(result).toMatchObject({
|
|
44
|
-
zipcode: '90001',
|
|
45
|
-
propertyusegroup: [
|
|
46
|
-
{
|
|
47
|
-
name: 'Commercial',
|
|
48
|
-
count: 2,
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
propertyusestandardized: [
|
|
52
|
-
{
|
|
53
|
-
name: 'Apartment house (5+ units)',
|
|
54
|
-
groupName: 'Commercial',
|
|
55
|
-
count: 1,
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: 'Auto repair, garage',
|
|
59
|
-
groupName: 'Commercial',
|
|
60
|
-
count: 1,
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
hvaccoolingdetail: [
|
|
64
|
-
{
|
|
65
|
-
name: 'Yes',
|
|
66
|
-
count: 1,
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
hvacheatingdetail: [
|
|
70
|
-
{
|
|
71
|
-
name: 'None',
|
|
72
|
-
count: 2,
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
utilitieswatersource: [],
|
|
76
|
-
utilitiessewageusage: [],
|
|
77
|
-
flooringmaterialprimary: [],
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
(0, globals_1.test)('should have single group with captial-case', async () => {
|
|
81
|
-
const result = await base.collection('filters').findOne({
|
|
82
|
-
zipcode: '90001',
|
|
83
|
-
});
|
|
84
|
-
(0, globals_1.expect)(result).not.toBe(null);
|
|
85
|
-
(0, globals_1.expect)(result?.propertyusegroup.length).toBe(1);
|
|
86
|
-
(0, globals_1.expect)(result?.propertyusegroup[0].name).toBe('Commercial');
|
|
87
|
-
(0, globals_1.expect)(result?.propertyusestandardized.every(({ groupName }) => groupName === 'Commercial')).toBeTruthy();
|
|
88
|
-
});
|
|
89
|
-
afterAll(async () => {
|
|
90
|
-
await (0, setup_1.closeConnection)();
|
|
91
|
-
});
|
|
92
|
-
});
|