@servicetitan/acquisition-functions 0.1.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/README.md +41 -0
- package/dist/__tests__/assessorlastsaledate-converter.test.js +85 -0
- package/dist/__tests__/filter-fetcher.test.js +85 -0
- package/dist/__tests__/mock.js +458 -0
- package/dist/__tests__/property-fix-use-group.test.js +63 -0
- package/dist/__tests__/setup.js +35 -0
- package/dist/filter-fetcher/calc-filter-count.js +83 -0
- package/dist/filter-fetcher/index.js +84 -0
- package/dist/fix-property-use/index.js +101 -0
- package/dist/index.js +18 -0
- package/dist/property-assessorlastsaledate-converter/index.js +102 -0
- package/dist/types.js +2 -0
- package/dist/utils/utils.js +80 -0
- package/dist/zip-processor.js +60 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @servicetitan/acquisition-functions
|
|
2
|
+
|
|
3
|
+
### Synopsis
|
|
4
|
+
|
|
5
|
+
This repo contains Marketing Acquisition properties & filters converters for MongoDB Atlas Functions
|
|
6
|
+
|
|
7
|
+
### Usage in functions
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
const { configureProcessor } = require('@servicetitan/acquisition-functions');
|
|
13
|
+
|
|
14
|
+
const { filterFetcher } = configureProcessor({
|
|
15
|
+
workers: 10,
|
|
16
|
+
mongoDb: mongoDbConnectionToDb,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
exports = async () => {
|
|
20
|
+
return filterFetcher.start('000000-999999');
|
|
21
|
+
};
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Run tests
|
|
25
|
+
|
|
26
|
+
Locally:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
docker-compose up -d mongo
|
|
30
|
+
npm run test
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
In Docker:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
# In root FE directory
|
|
37
|
+
lerna run build --scope=@servicetitan/acquisition-functions
|
|
38
|
+
|
|
39
|
+
# In package directory
|
|
40
|
+
docker-compose up
|
|
41
|
+
```
|
|
@@ -0,0 +1,85 @@
|
|
|
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
|
+
(0, globals_1.beforeAll)(async () => {
|
|
10
|
+
const client = await (0, setup_1.openConnection)();
|
|
11
|
+
base = client.db('test');
|
|
12
|
+
});
|
|
13
|
+
describe('processor', () => {
|
|
14
|
+
(0, globals_1.beforeEach)(async () => {
|
|
15
|
+
await (0, setup_1.setupProperties)(base);
|
|
16
|
+
processor = (0, index_1.configureProcessor)({
|
|
17
|
+
workers: 1,
|
|
18
|
+
mongoDb: base,
|
|
19
|
+
});
|
|
20
|
+
const { assessorLastSaleDateProcessor } = processor;
|
|
21
|
+
await assessorLastSaleDateProcessor.start('90001');
|
|
22
|
+
});
|
|
23
|
+
(0, globals_1.test)('should convert existing field to date', async () => {
|
|
24
|
+
const result = await new Promise(resolve => {
|
|
25
|
+
base.collection('properties')
|
|
26
|
+
.find({
|
|
27
|
+
assessorlastsaledate: {
|
|
28
|
+
$exists: true,
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
.toArray((err, res) => {
|
|
32
|
+
resolve(res);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
(0, globals_1.expect)(result[0].assessorlastsaledate).toBeInstanceOf(Date);
|
|
36
|
+
});
|
|
37
|
+
(0, globals_1.test)('should not touch nulls', async () => {
|
|
38
|
+
const result = await new Promise(resolve => {
|
|
39
|
+
base.collection('properties')
|
|
40
|
+
.find({
|
|
41
|
+
assessorlastsaledate: null,
|
|
42
|
+
})
|
|
43
|
+
.toArray((err, res) => {
|
|
44
|
+
resolve(res);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
(0, globals_1.expect)(result[0].assessorlastsaledate).toBe(null);
|
|
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 new Promise(resolve => {
|
|
57
|
+
base.collection('properties')
|
|
58
|
+
.find({
|
|
59
|
+
assessorlastsaledate: {
|
|
60
|
+
$exists: true,
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
.toArray((err, res) => {
|
|
64
|
+
resolve(res);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
(0, globals_1.expect)(result[0].assessorlastsaledate).toBeInstanceOf(Date);
|
|
68
|
+
});
|
|
69
|
+
(0, globals_1.test)('should not touch nulls', async () => {
|
|
70
|
+
const result = await new Promise(resolve => {
|
|
71
|
+
base.collection('properties')
|
|
72
|
+
.find({
|
|
73
|
+
assessorlastsaledate: null,
|
|
74
|
+
})
|
|
75
|
+
.toArray((err, res) => {
|
|
76
|
+
resolve(res);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
(0, globals_1.expect)(result[0].assessorlastsaledate).toBe(null);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
afterAll(async () => {
|
|
83
|
+
await (0, setup_1.closeConnection)();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
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
|
+
(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
|
+
processor = (0, index_1.configureProcessor)({
|
|
14
|
+
workers: 10,
|
|
15
|
+
mongoDb: base,
|
|
16
|
+
});
|
|
17
|
+
const { filterFetcher, propertyUseGroupProcessor } = processor;
|
|
18
|
+
await propertyUseGroupProcessor.start('90001');
|
|
19
|
+
await filterFetcher.start('90001-90002');
|
|
20
|
+
});
|
|
21
|
+
(0, globals_1.test)('should have empty filter for missing zip', async () => {
|
|
22
|
+
const result = await base.collection('filters').findOne({
|
|
23
|
+
zipcode: '90002',
|
|
24
|
+
});
|
|
25
|
+
(0, globals_1.expect)(result).not.toBe(null);
|
|
26
|
+
(0, globals_1.expect)(result?.propertyusegroup.length).toBe(0);
|
|
27
|
+
(0, globals_1.expect)(result?.flooringmaterialprimary.length).toBe(0);
|
|
28
|
+
(0, globals_1.expect)(result?.hvaccoolingdetail.length).toBe(0);
|
|
29
|
+
(0, globals_1.expect)(result?.hvacheatingdetail.length).toBe(0);
|
|
30
|
+
(0, globals_1.expect)(result?.propertyusestandardized.length).toBe(0);
|
|
31
|
+
(0, globals_1.expect)(result?.utilitieswatersource.length).toBe(0);
|
|
32
|
+
});
|
|
33
|
+
(0, globals_1.test)('should form correct filter', async () => {
|
|
34
|
+
const result = await base.collection('filters').findOne({
|
|
35
|
+
zipcode: '90001',
|
|
36
|
+
});
|
|
37
|
+
(0, globals_1.expect)(result).toMatchObject({
|
|
38
|
+
zipcode: '90001',
|
|
39
|
+
propertyusegroup: [
|
|
40
|
+
{
|
|
41
|
+
name: 'COMMERCIAL',
|
|
42
|
+
count: 2,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
propertyusestandardized: [
|
|
46
|
+
{
|
|
47
|
+
name: 'APARTMENT HOUSE (5+ UNITS)',
|
|
48
|
+
groupName: 'COMMERCIAL',
|
|
49
|
+
count: 1,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'AUTO REPAIR, GARAGE',
|
|
53
|
+
groupName: 'COMMERCIAL',
|
|
54
|
+
count: 1,
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
hvaccoolingdetail: [
|
|
58
|
+
{
|
|
59
|
+
name: 'YES',
|
|
60
|
+
count: 1,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
hvacheatingdetail: [
|
|
64
|
+
{
|
|
65
|
+
name: 'NONE',
|
|
66
|
+
count: 2,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
utilitieswatersource: [],
|
|
70
|
+
flooringmaterialprimary: [],
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
(0, globals_1.test)('should have single group with captial-case', async () => {
|
|
74
|
+
const result = await base.collection('filters').findOne({
|
|
75
|
+
zipcode: '90001',
|
|
76
|
+
});
|
|
77
|
+
(0, globals_1.expect)(result).not.toBe(null);
|
|
78
|
+
(0, globals_1.expect)(result?.propertyusegroup.length).toBe(1);
|
|
79
|
+
(0, globals_1.expect)(result?.propertyusegroup[0].name).toBe('COMMERCIAL');
|
|
80
|
+
(0, globals_1.expect)(result?.propertyusestandardized.every(({ groupName }) => groupName === 'COMMERCIAL')).toBeTruthy();
|
|
81
|
+
});
|
|
82
|
+
afterAll(async () => {
|
|
83
|
+
await (0, setup_1.closeConnection)();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MOCK = void 0;
|
|
4
|
+
/* eslint-disable */
|
|
5
|
+
exports.MOCK = [
|
|
6
|
+
{
|
|
7
|
+
attomid: 154817956,
|
|
8
|
+
fulladdress: '7310 S Central Ave Los Angeles CA 90001',
|
|
9
|
+
addressstreet: '7310 S Central Ave',
|
|
10
|
+
addressunit: ' ',
|
|
11
|
+
primarynumber: 7310,
|
|
12
|
+
streetname: 'Central',
|
|
13
|
+
streetpredirection: 'S',
|
|
14
|
+
streetpostdirection: '',
|
|
15
|
+
streetsuffix: 'Ave',
|
|
16
|
+
secondarynumber: '',
|
|
17
|
+
secondarydesignator: '',
|
|
18
|
+
extrasecondarynumber: '',
|
|
19
|
+
extrasecondarydesignator: '',
|
|
20
|
+
cityname: 'Los Angeles',
|
|
21
|
+
stateabbreviation: 'CA',
|
|
22
|
+
zipcode: '90001',
|
|
23
|
+
latitude: 33.97346,
|
|
24
|
+
longitude: -118.25645,
|
|
25
|
+
situsstatecode: 'CA',
|
|
26
|
+
situscounty: 'Los Angeles',
|
|
27
|
+
propertyjurisdictionname: 'LOS ANGELES',
|
|
28
|
+
situsstatecountyfips: '06037',
|
|
29
|
+
combinedstatisticalarea: 'Los Angeles-Long Beach, CA',
|
|
30
|
+
cbsaname: 'LOS ANGELES-LONG BEACH-SANTA ANA, CA METROPOLITAN STATISTICAL AREA',
|
|
31
|
+
cbsacode: 31100,
|
|
32
|
+
msaname: 'LOS ANGELES-LONG BEACH-SANTA ANA, CA',
|
|
33
|
+
msacode: 31100,
|
|
34
|
+
metropolitandivision: 'LOS ANGELES-LONG BEACH-GLENDALE, CA METROPOLITAN DIVISION',
|
|
35
|
+
minorcivildivisionname: 'SOUTH GATE-EAST LOS ANGELES',
|
|
36
|
+
minorcivildivisioncode: 93155,
|
|
37
|
+
neighborhoodcode: '',
|
|
38
|
+
censusfipsplacecode: 24477,
|
|
39
|
+
censustract: 535001,
|
|
40
|
+
censusblockgroup: 1,
|
|
41
|
+
censusblock: 1001,
|
|
42
|
+
parcelnumberraw: '6024-003-903',
|
|
43
|
+
parcelnumberformatted: '',
|
|
44
|
+
parcelnumberyearadded: 0,
|
|
45
|
+
parcelnumberalternate: '',
|
|
46
|
+
parcelmapbook: '',
|
|
47
|
+
parcelmappage: '',
|
|
48
|
+
parcelnumberyearchange: 2008,
|
|
49
|
+
parcelnumberprevious: 6024003003,
|
|
50
|
+
parcelaccountnumber: '',
|
|
51
|
+
propertyaddressfull: '7310 S CENTRAL AVE',
|
|
52
|
+
propertyaddresshousenumber: 7310,
|
|
53
|
+
propertyaddressstreetdirection: 'S',
|
|
54
|
+
propertyaddressstreetname: 'CENTRAL',
|
|
55
|
+
propertyaddressstreetsuffix: 'AVE',
|
|
56
|
+
propertyaddressstreetpostdirection: '',
|
|
57
|
+
propertyaddressunitprefix: '',
|
|
58
|
+
propertyaddressunitvalue: '',
|
|
59
|
+
propertyaddresscity: 'LOS ANGELES',
|
|
60
|
+
propertyaddressstate: 'CA',
|
|
61
|
+
propertyaddresszip: 90001,
|
|
62
|
+
propertyaddresszip4: 2423,
|
|
63
|
+
propertyaddresscrrt: 'C002',
|
|
64
|
+
propertyaddressinfoprivacy: 0,
|
|
65
|
+
congressionaldistricthouse: 53,
|
|
66
|
+
legaldescription: 'TR=5450 LOT 803',
|
|
67
|
+
legalrange: '',
|
|
68
|
+
legaltownship: '',
|
|
69
|
+
legalsection: '',
|
|
70
|
+
legalquarter: '',
|
|
71
|
+
legalquarterquarter: '',
|
|
72
|
+
legalsubdivision: 5450,
|
|
73
|
+
legalphase: '',
|
|
74
|
+
legaltractnumber: 5450,
|
|
75
|
+
legalblock1: '',
|
|
76
|
+
legalblock2: '',
|
|
77
|
+
legallotnumber1: 803,
|
|
78
|
+
legallotnumber2: '',
|
|
79
|
+
legallotnumber3: '',
|
|
80
|
+
legalunit: '',
|
|
81
|
+
partyowner1namefull: 'L A UNIFIED SCHOOL DIST',
|
|
82
|
+
partyowner1namefirst: '',
|
|
83
|
+
partyowner1namemiddle: '',
|
|
84
|
+
partyowner1namelast: 'L A UNIFIED SCHOOL DIST',
|
|
85
|
+
partyowner1namesuffix: '',
|
|
86
|
+
trustdescription: '',
|
|
87
|
+
companyflag: 'The Owner is Determine to be a Company',
|
|
88
|
+
partyowner2namefull: '',
|
|
89
|
+
partyowner2namefirst: '',
|
|
90
|
+
partyowner2namemiddle: '',
|
|
91
|
+
partyowner2namelast: '',
|
|
92
|
+
partyowner2namesuffix: '',
|
|
93
|
+
ownertypedescription1: 'COMPANY',
|
|
94
|
+
ownershipvestingrelationcode: '',
|
|
95
|
+
partyowner3namefull: '',
|
|
96
|
+
partyowner3namefirst: '',
|
|
97
|
+
partyowner3namemiddle: '',
|
|
98
|
+
partyowner3namelast: '',
|
|
99
|
+
partyowner3namesuffix: '',
|
|
100
|
+
partyowner4namefull: '',
|
|
101
|
+
partyowner4namefirst: '',
|
|
102
|
+
partyowner4namemiddle: '',
|
|
103
|
+
partyowner4namelast: '',
|
|
104
|
+
partyowner4namesuffix: '',
|
|
105
|
+
ownertypedescription2: 'NP',
|
|
106
|
+
contactownermailingcounty: 'LOS ANGELES',
|
|
107
|
+
contactownermailingfips: '06037',
|
|
108
|
+
contactownermailaddressfull: '333 S BEAUDRY AVE',
|
|
109
|
+
contactownermailaddresshousenumber: 333,
|
|
110
|
+
contactownermailaddressstreetdirection: 'S',
|
|
111
|
+
contactownermailaddressstreetname: 'BEAUDRY',
|
|
112
|
+
contactownermailaddressstreetsuffix: 'AVE',
|
|
113
|
+
contactownermailaddressstreetpostdirection: '',
|
|
114
|
+
contactownermailaddressunitprefix: '',
|
|
115
|
+
contactownermailaddressunit: '',
|
|
116
|
+
contactownermailaddresscity: 'LOS ANGELES',
|
|
117
|
+
contactownermailaddressstate: 'CA',
|
|
118
|
+
contactownermailaddresszip: 90017,
|
|
119
|
+
contactownermailaddresszip4: 1466,
|
|
120
|
+
contactownermailaddresscrrt: 'C006',
|
|
121
|
+
contactownermailaddressinfoformat: 'H',
|
|
122
|
+
contactownermailinfoprivacy: '',
|
|
123
|
+
statusowneroccupiedflag: 'unknown',
|
|
124
|
+
deedowner1namefull: 'L A UNIFIED SCHOOL DIST',
|
|
125
|
+
deedowner1namefirst: '',
|
|
126
|
+
deedowner1namemiddle: '',
|
|
127
|
+
deedowner1namelast: 'L A UNIFIED SCHOOL DIST',
|
|
128
|
+
deedowner1namesuffix: '',
|
|
129
|
+
deedowner2namefull: '',
|
|
130
|
+
deedowner2namefirst: '',
|
|
131
|
+
deedowner2namemiddle: '',
|
|
132
|
+
deedowner2namelast: '',
|
|
133
|
+
deedowner2namesuffix: '',
|
|
134
|
+
deedowner3namefull: '',
|
|
135
|
+
deedowner3namefirst: '',
|
|
136
|
+
deedowner3namemiddle: '',
|
|
137
|
+
deedowner3namelast: '',
|
|
138
|
+
deedowner3namesuffix: '',
|
|
139
|
+
deedowner4namefull: '',
|
|
140
|
+
deedowner4namefirst: '',
|
|
141
|
+
deedowner4namemiddle: '',
|
|
142
|
+
deedowner4namelast: '',
|
|
143
|
+
deedowner4namesuffix: '',
|
|
144
|
+
taxyearassessed: 2021,
|
|
145
|
+
taxassessedvaluetotal: 19483,
|
|
146
|
+
taxassessedvalueimprovements: 0,
|
|
147
|
+
taxassessedvalueland: 19483,
|
|
148
|
+
taxassessedimprovementsperc: 0,
|
|
149
|
+
previousassessedvalue: 19483,
|
|
150
|
+
taxmarketvalueyear: 0,
|
|
151
|
+
taxmarketvaluetotal: 0,
|
|
152
|
+
taxmarketvalueimprovements: 0,
|
|
153
|
+
taxmarketvalueland: 0,
|
|
154
|
+
taxmarketimprovementsperc: 0,
|
|
155
|
+
taxfiscalyear: 2020,
|
|
156
|
+
taxratearea: '1-265',
|
|
157
|
+
taxbilledamount: 0,
|
|
158
|
+
taxdelinquentyear: 0,
|
|
159
|
+
lastassessortaxrollupdate: '2021-07-01T00:00:00.000Z',
|
|
160
|
+
assrlastupdated: '2021-09-20T00:00:00.000Z',
|
|
161
|
+
taxexemptionadditional: '',
|
|
162
|
+
yearbuilt: 1928,
|
|
163
|
+
yearbuilteffective: 1928,
|
|
164
|
+
zonedcodelocal: 'LCC3*',
|
|
165
|
+
propertyusemuni: '0500',
|
|
166
|
+
propertyusegroup: 'COMMERCIAL',
|
|
167
|
+
propertyusestandardized: 'APARTMENT HOUSE (5+ UNITS)',
|
|
168
|
+
assessorlastsaledate: '2006-08-04T00:00:00.000Z',
|
|
169
|
+
assessorlastsaleamount: 0,
|
|
170
|
+
assessorpriorsaledate: '2006-08-04T00:00:00.000Z',
|
|
171
|
+
assessorpriorsaleamount: 0,
|
|
172
|
+
lastownershiptransferdate: '2006-08-04T00:00:00.000Z',
|
|
173
|
+
lastownershiptransferdocumentnumber: '2006-1731837',
|
|
174
|
+
lastownershiptransfertransactionid: 199634356,
|
|
175
|
+
deedlastsaledocumentbook: '',
|
|
176
|
+
deedlastsaledocumentpage: '',
|
|
177
|
+
deedlastdocumentnumber: '2006-1731837',
|
|
178
|
+
deedlastsaledate: '2006-08-04T00:00:00.000Z',
|
|
179
|
+
deedlastsaleprice: 0,
|
|
180
|
+
deedlastsaletransactionid: 199634356,
|
|
181
|
+
areabuilding: 3200,
|
|
182
|
+
areabuildingdefinitioncode: 'Total Area',
|
|
183
|
+
areagross: 3200,
|
|
184
|
+
area1stfloor: 0,
|
|
185
|
+
area2ndfloor: 0,
|
|
186
|
+
areaupperfloors: 0,
|
|
187
|
+
arealotacres: 0.0933425,
|
|
188
|
+
arealotsf: 4066,
|
|
189
|
+
arealotdepth: 0,
|
|
190
|
+
arealotwidth: 0,
|
|
191
|
+
roomsatticarea: 0,
|
|
192
|
+
roomsatticflag: 0,
|
|
193
|
+
roomsbasementarea: 0,
|
|
194
|
+
roomsbasementareafinished: 0,
|
|
195
|
+
roomsbasementareaunfinished: 0,
|
|
196
|
+
parkinggarage: 'Unknown',
|
|
197
|
+
parkinggaragearea: 0,
|
|
198
|
+
parkingcarport: 0,
|
|
199
|
+
parkingcarportarea: 0,
|
|
200
|
+
hvaccoolingdetail: 'YES',
|
|
201
|
+
hvacheatingdetail: 'NONE',
|
|
202
|
+
hvacheatingfuel: 'unknown',
|
|
203
|
+
utilitiessewageusage: 'unknown',
|
|
204
|
+
utilitieswatersource: 'unknown',
|
|
205
|
+
utilitiesmobilehomehookupflag: 'UNKNOWN',
|
|
206
|
+
foundation: 'unknown',
|
|
207
|
+
construction: 'UNKNOWN',
|
|
208
|
+
interiorstructure: 'unknown',
|
|
209
|
+
plumbingfixturescount: 0,
|
|
210
|
+
constructionfireresistanceclass: '',
|
|
211
|
+
assafetyfiresprinklersflag: 'UNKNOWN',
|
|
212
|
+
flooringmaterialprimary: 'unknown',
|
|
213
|
+
bathcount: 0,
|
|
214
|
+
bathpartialcount: 0,
|
|
215
|
+
bedroomscount: 0,
|
|
216
|
+
roomscount: 0,
|
|
217
|
+
storiescount: 0,
|
|
218
|
+
unitscount: 6,
|
|
219
|
+
fireplace: 'unknown',
|
|
220
|
+
fireplacecount: 0,
|
|
221
|
+
structurestyle: 'unknown',
|
|
222
|
+
exterior1code: 'UNKNOWN',
|
|
223
|
+
roofmaterial: 'unknown',
|
|
224
|
+
roofconstruction: 'unknown',
|
|
225
|
+
porchcode: 'unknown',
|
|
226
|
+
pool: 'UNKNOWN',
|
|
227
|
+
poolarea: 0,
|
|
228
|
+
buildingscount: 0,
|
|
229
|
+
modifiedon: '2021-09-14T00:00:00T00:00:00.000Z',
|
|
230
|
+
location: '33.97346,-118.25645',
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
attomid: 154816509,
|
|
234
|
+
fulladdress: '6602 S Central Ave Los Angeles CA 90001',
|
|
235
|
+
addressstreet: '6602 S Central Ave',
|
|
236
|
+
addressunit: ' ',
|
|
237
|
+
primarynumber: 6602,
|
|
238
|
+
streetname: 'Central',
|
|
239
|
+
streetpredirection: 'S',
|
|
240
|
+
streetpostdirection: '',
|
|
241
|
+
streetsuffix: 'Ave',
|
|
242
|
+
secondarynumber: '',
|
|
243
|
+
secondarydesignator: '',
|
|
244
|
+
extrasecondarynumber: '',
|
|
245
|
+
extrasecondarydesignator: '',
|
|
246
|
+
cityname: 'Los Angeles',
|
|
247
|
+
stateabbreviation: 'CA',
|
|
248
|
+
zipcode: '90001',
|
|
249
|
+
latitude: 33.97984,
|
|
250
|
+
longitude: -118.25633,
|
|
251
|
+
situsstatecode: 'CA',
|
|
252
|
+
situscounty: 'Los Angeles',
|
|
253
|
+
propertyjurisdictionname: 'LOS ANGELES',
|
|
254
|
+
situsstatecountyfips: '06037',
|
|
255
|
+
combinedstatisticalarea: 'Los Angeles-Long Beach, CA',
|
|
256
|
+
cbsaname: 'LOS ANGELES-LONG BEACH-SANTA ANA, CA METROPOLITAN STATISTICAL AREA',
|
|
257
|
+
cbsacode: 31100,
|
|
258
|
+
msaname: 'LOS ANGELES-LONG BEACH-SANTA ANA, CA',
|
|
259
|
+
msacode: 31100,
|
|
260
|
+
metropolitandivision: 'LOS ANGELES-LONG BEACH-GLENDALE, CA METROPOLITAN DIVISION',
|
|
261
|
+
minorcivildivisionname: 'SOUTH GATE-EAST LOS ANGELES',
|
|
262
|
+
minorcivildivisioncode: 93155,
|
|
263
|
+
neighborhoodcode: '',
|
|
264
|
+
censusfipsplacecode: 24477,
|
|
265
|
+
censustract: 532900,
|
|
266
|
+
censusblockgroup: 3,
|
|
267
|
+
censusblock: 3000,
|
|
268
|
+
parcelnumberraw: '6010-005-002',
|
|
269
|
+
parcelnumberformatted: '',
|
|
270
|
+
parcelnumberyearadded: 0,
|
|
271
|
+
parcelnumberalternate: '',
|
|
272
|
+
parcelmapbook: '',
|
|
273
|
+
parcelmappage: '',
|
|
274
|
+
parcelnumberyearchange: 0,
|
|
275
|
+
parcelnumberprevious: '',
|
|
276
|
+
parcelaccountnumber: '',
|
|
277
|
+
propertyaddressfull: '6602 S CENTRAL AVE',
|
|
278
|
+
propertyaddresshousenumber: 6602,
|
|
279
|
+
propertyaddressstreetdirection: 'S',
|
|
280
|
+
propertyaddressstreetname: 'CENTRAL',
|
|
281
|
+
propertyaddressstreetsuffix: 'AVE',
|
|
282
|
+
propertyaddressstreetpostdirection: '',
|
|
283
|
+
propertyaddressunitprefix: '',
|
|
284
|
+
propertyaddressunitvalue: '',
|
|
285
|
+
propertyaddresscity: 'LOS ANGELES',
|
|
286
|
+
propertyaddressstate: 'CA',
|
|
287
|
+
propertyaddresszip: 90001,
|
|
288
|
+
propertyaddresszip4: '',
|
|
289
|
+
propertyaddresscrrt: '',
|
|
290
|
+
propertyaddressinfoprivacy: 0,
|
|
291
|
+
congressionaldistricthouse: 0,
|
|
292
|
+
legaldescription: 'TRACT NO 5450 E 50 FT OF LOT 33',
|
|
293
|
+
legalrange: '',
|
|
294
|
+
legaltownship: '',
|
|
295
|
+
legalsection: '',
|
|
296
|
+
legalquarter: '',
|
|
297
|
+
legalquarterquarter: '',
|
|
298
|
+
legalsubdivision: 5450,
|
|
299
|
+
legalphase: '',
|
|
300
|
+
legaltractnumber: 5450,
|
|
301
|
+
legalblock1: '',
|
|
302
|
+
legalblock2: '',
|
|
303
|
+
legallotnumber1: 33,
|
|
304
|
+
legallotnumber2: '',
|
|
305
|
+
legallotnumber3: '',
|
|
306
|
+
legalunit: '',
|
|
307
|
+
partyowner1namefull: 'LEVI JONES',
|
|
308
|
+
partyowner1namefirst: 'LEVI',
|
|
309
|
+
partyowner1namemiddle: '',
|
|
310
|
+
partyowner1namelast: 'JONES',
|
|
311
|
+
partyowner1namesuffix: '',
|
|
312
|
+
trustdescription: '',
|
|
313
|
+
companyflag: 'unknown',
|
|
314
|
+
partyowner2namefull: '',
|
|
315
|
+
partyowner2namefirst: '',
|
|
316
|
+
partyowner2namemiddle: '',
|
|
317
|
+
partyowner2namelast: '',
|
|
318
|
+
partyowner2namesuffix: '',
|
|
319
|
+
ownertypedescription1: 'INDIVIDUAL',
|
|
320
|
+
ownershipvestingrelationcode: '',
|
|
321
|
+
partyowner3namefull: 'LEVI & ANNABELLE JONES TRUST',
|
|
322
|
+
partyowner3namefirst: '',
|
|
323
|
+
partyowner3namemiddle: '',
|
|
324
|
+
partyowner3namelast: 'LEVI & ANNABELLE JONES TRUST',
|
|
325
|
+
partyowner3namesuffix: '',
|
|
326
|
+
partyowner4namefull: '',
|
|
327
|
+
partyowner4namefirst: '',
|
|
328
|
+
partyowner4namemiddle: '',
|
|
329
|
+
partyowner4namelast: '',
|
|
330
|
+
partyowner4namesuffix: '',
|
|
331
|
+
ownertypedescription2: 'COMPANY',
|
|
332
|
+
contactownermailingcounty: 'LOS ANGELES',
|
|
333
|
+
contactownermailingfips: '06037',
|
|
334
|
+
contactownermailaddressfull: '6534 S CENTRAL AVE',
|
|
335
|
+
contactownermailaddresshousenumber: 6534,
|
|
336
|
+
contactownermailaddressstreetdirection: 'S',
|
|
337
|
+
contactownermailaddressstreetname: 'CENTRAL',
|
|
338
|
+
contactownermailaddressstreetsuffix: 'AVE',
|
|
339
|
+
contactownermailaddressstreetpostdirection: '',
|
|
340
|
+
contactownermailaddressunitprefix: '',
|
|
341
|
+
contactownermailaddressunit: '',
|
|
342
|
+
contactownermailaddresscity: 'LOS ANGELES',
|
|
343
|
+
contactownermailaddressstate: 'CA',
|
|
344
|
+
contactownermailaddresszip: 90001,
|
|
345
|
+
contactownermailaddresszip4: 1642,
|
|
346
|
+
contactownermailaddresscrrt: 'C043',
|
|
347
|
+
contactownermailaddressinfoformat: 'S',
|
|
348
|
+
contactownermailinfoprivacy: '',
|
|
349
|
+
statusowneroccupiedflag: 'Not Owner Occupied or Unknown',
|
|
350
|
+
deedowner1namefull: 'LEVI & ANNABELLE JONES TRUST',
|
|
351
|
+
deedowner1namefirst: '',
|
|
352
|
+
deedowner1namemiddle: '',
|
|
353
|
+
deedowner1namelast: 'LEVI & ANNABELLE JONES TRUST',
|
|
354
|
+
deedowner1namesuffix: '',
|
|
355
|
+
deedowner2namefull: '',
|
|
356
|
+
deedowner2namefirst: '',
|
|
357
|
+
deedowner2namemiddle: '',
|
|
358
|
+
deedowner2namelast: '',
|
|
359
|
+
deedowner2namesuffix: '',
|
|
360
|
+
deedowner3namefull: '',
|
|
361
|
+
deedowner3namefirst: '',
|
|
362
|
+
deedowner3namemiddle: '',
|
|
363
|
+
deedowner3namelast: '',
|
|
364
|
+
deedowner3namesuffix: '',
|
|
365
|
+
deedowner4namefull: '',
|
|
366
|
+
deedowner4namefirst: '',
|
|
367
|
+
deedowner4namemiddle: '',
|
|
368
|
+
deedowner4namelast: '',
|
|
369
|
+
deedowner4namesuffix: '',
|
|
370
|
+
taxyearassessed: 2021,
|
|
371
|
+
taxassessedvaluetotal: 10579,
|
|
372
|
+
taxassessedvalueimprovements: 4718,
|
|
373
|
+
taxassessedvalueland: 5861,
|
|
374
|
+
taxassessedimprovementsperc: 44,
|
|
375
|
+
previousassessedvalue: 10579,
|
|
376
|
+
taxmarketvalueyear: 0,
|
|
377
|
+
taxmarketvaluetotal: 0,
|
|
378
|
+
taxmarketvalueimprovements: 0,
|
|
379
|
+
taxmarketvalueland: 0,
|
|
380
|
+
taxmarketimprovementsperc: 0,
|
|
381
|
+
taxfiscalyear: 2021,
|
|
382
|
+
taxratearea: '1-166',
|
|
383
|
+
taxbilledamount: 1216.77,
|
|
384
|
+
taxdelinquentyear: 0,
|
|
385
|
+
lastassessortaxrollupdate: '2021-07-01T00:00:00.000Z',
|
|
386
|
+
assrlastupdated: '2021-10-11T00:00:00.000Z',
|
|
387
|
+
taxexemptionadditional: '',
|
|
388
|
+
yearbuilt: 1950,
|
|
389
|
+
yearbuilteffective: 1951,
|
|
390
|
+
zonedcodelocal: 'LCM1*',
|
|
391
|
+
propertyusemuni: 2600,
|
|
392
|
+
propertyusegroup: 'Commercial',
|
|
393
|
+
propertyusestandardized: 'AUTO REPAIR, GARAGE',
|
|
394
|
+
assessorlastsaledate: null,
|
|
395
|
+
assessorlastsaleamount: 0,
|
|
396
|
+
assessorpriorsaledate: null,
|
|
397
|
+
assessorpriorsaleamount: 0,
|
|
398
|
+
lastownershiptransferdate: '1996-06-20T00:00:00.000Z',
|
|
399
|
+
lastownershiptransferdocumentnumber: '96-0972167',
|
|
400
|
+
lastownershiptransfertransactionid: 0,
|
|
401
|
+
deedlastsaledocumentbook: '',
|
|
402
|
+
deedlastsaledocumentpage: '',
|
|
403
|
+
deedlastdocumentnumber: '',
|
|
404
|
+
deedlastsaledate: null,
|
|
405
|
+
deedlastsaleprice: 0,
|
|
406
|
+
deedlastsaletransactionid: 0,
|
|
407
|
+
areabuilding: 760,
|
|
408
|
+
areabuildingdefinitioncode: 'Total Area',
|
|
409
|
+
areagross: 760,
|
|
410
|
+
area1stfloor: 0,
|
|
411
|
+
area2ndfloor: 0,
|
|
412
|
+
areaupperfloors: 0,
|
|
413
|
+
arealotacres: 0.0463499,
|
|
414
|
+
arealotsf: 2019,
|
|
415
|
+
arealotdepth: 0,
|
|
416
|
+
arealotwidth: 0,
|
|
417
|
+
roomsatticarea: 0,
|
|
418
|
+
roomsatticflag: 0,
|
|
419
|
+
roomsbasementarea: 0,
|
|
420
|
+
roomsbasementareafinished: 0,
|
|
421
|
+
roomsbasementareaunfinished: 0,
|
|
422
|
+
parkinggarage: 'Unknown',
|
|
423
|
+
parkinggaragearea: 0,
|
|
424
|
+
parkingcarport: 0,
|
|
425
|
+
parkingcarportarea: 0,
|
|
426
|
+
hvaccoolingdetail: 'unknown',
|
|
427
|
+
hvacheatingdetail: 'NONE',
|
|
428
|
+
hvacheatingfuel: 'unknown',
|
|
429
|
+
utilitiessewageusage: 'unknown',
|
|
430
|
+
utilitieswatersource: 'unknown',
|
|
431
|
+
utilitiesmobilehomehookupflag: 'UNKNOWN',
|
|
432
|
+
foundation: 'unknown',
|
|
433
|
+
construction: 'WOOD',
|
|
434
|
+
interiorstructure: 'unknown',
|
|
435
|
+
plumbingfixturescount: 0,
|
|
436
|
+
constructionfireresistanceclass: 104,
|
|
437
|
+
assafetyfiresprinklersflag: 'UNKNOWN',
|
|
438
|
+
flooringmaterialprimary: 'unknown',
|
|
439
|
+
bathcount: 0,
|
|
440
|
+
bathpartialcount: 0,
|
|
441
|
+
bedroomscount: 0,
|
|
442
|
+
roomscount: 0,
|
|
443
|
+
storiescount: 1,
|
|
444
|
+
unitscount: 0,
|
|
445
|
+
fireplace: 'unknown',
|
|
446
|
+
fireplacecount: 0,
|
|
447
|
+
structurestyle: 'unknown',
|
|
448
|
+
exterior1code: 'UNKNOWN',
|
|
449
|
+
roofmaterial: 'unknown',
|
|
450
|
+
roofconstruction: 'unknown',
|
|
451
|
+
porchcode: 'unknown',
|
|
452
|
+
pool: 'UNKNOWN',
|
|
453
|
+
poolarea: 0,
|
|
454
|
+
buildingscount: 0,
|
|
455
|
+
modifiedon: '2021-10-22T00:00:00T00:00:00.000Z',
|
|
456
|
+
location: '33.97984,-118.25633',
|
|
457
|
+
},
|
|
458
|
+
];
|
|
@@ -0,0 +1,63 @@
|
|
|
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-use-group-converter', () => {
|
|
7
|
+
let base;
|
|
8
|
+
(0, globals_1.beforeAll)(async () => {
|
|
9
|
+
const client = await (0, setup_1.openConnection)();
|
|
10
|
+
base = client.db('test');
|
|
11
|
+
});
|
|
12
|
+
describe('processor', () => {
|
|
13
|
+
let processor;
|
|
14
|
+
(0, globals_1.beforeAll)(async () => {
|
|
15
|
+
await (0, setup_1.setupProperties)(base);
|
|
16
|
+
processor = (0, index_1.configureProcessor)({
|
|
17
|
+
workers: 1,
|
|
18
|
+
mongoDb: base,
|
|
19
|
+
});
|
|
20
|
+
const { propertyUseGroupProcessor } = processor;
|
|
21
|
+
await propertyUseGroupProcessor.start('90001-90002');
|
|
22
|
+
});
|
|
23
|
+
(0, globals_1.test)('should convert existing field to captial-case', async () => {
|
|
24
|
+
const result = await new Promise(resolve => {
|
|
25
|
+
base.collection('properties')
|
|
26
|
+
.find({
|
|
27
|
+
propertyusegroup: {
|
|
28
|
+
$exists: true,
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
.toArray((err, res) => {
|
|
32
|
+
resolve(res);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
(0, globals_1.expect)(result[0].propertyusegroup).toBe('COMMERCIAL');
|
|
36
|
+
(0, globals_1.expect)(result[1].propertyusegroup).toBe('COMMERCIAL');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('aggregate', () => {
|
|
40
|
+
(0, globals_1.beforeAll)(async () => {
|
|
41
|
+
await (0, setup_1.setupProperties)(base);
|
|
42
|
+
});
|
|
43
|
+
(0, globals_1.test)('should convert existing field to captial-case', async () => {
|
|
44
|
+
await (0, index_1.propertyUseGroupProcessorAggregate)(base);
|
|
45
|
+
const result = await new Promise(resolve => {
|
|
46
|
+
base.collection('properties')
|
|
47
|
+
.find({
|
|
48
|
+
propertyusegroup: {
|
|
49
|
+
$exists: true,
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
.toArray((err, res) => {
|
|
53
|
+
resolve(res);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
(0, globals_1.expect)(result[0].propertyusegroup).toBe('COMMERCIAL');
|
|
57
|
+
(0, globals_1.expect)(result[1].propertyusegroup).toBe('COMMERCIAL');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
afterAll(async () => {
|
|
61
|
+
await (0, setup_1.closeConnection)();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.closeConnection = exports.openConnection = exports.setupProperties = void 0;
|
|
4
|
+
const mongodb_1 = require("mongodb");
|
|
5
|
+
const mock_1 = require("./mock");
|
|
6
|
+
async function setupProperties(base) {
|
|
7
|
+
try {
|
|
8
|
+
await base.dropCollection('properties');
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
// ignore
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
await base.createCollection('properties');
|
|
15
|
+
await base.collection('properties').insertMany(mock_1.MOCK);
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
// ignore
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.setupProperties = setupProperties;
|
|
22
|
+
const url = `mongodb://${process.env.MONGO_HOSTNAME ?? 'localhost'}:27017`;
|
|
23
|
+
const mongoClient = new mongodb_1.MongoClient(url, {
|
|
24
|
+
useNewUrlParser: true,
|
|
25
|
+
useUnifiedTopology: true,
|
|
26
|
+
poolSize: 60,
|
|
27
|
+
});
|
|
28
|
+
let connectedMongoClient;
|
|
29
|
+
const openConnection = async () => {
|
|
30
|
+
connectedMongoClient = await mongoClient.connect();
|
|
31
|
+
return connectedMongoClient;
|
|
32
|
+
};
|
|
33
|
+
exports.openConnection = openConnection;
|
|
34
|
+
const closeConnection = () => connectedMongoClient?.close();
|
|
35
|
+
exports.closeConnection = closeConnection;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateFilterCount = void 0;
|
|
4
|
+
const utils_1 = require("../utils/utils");
|
|
5
|
+
const calculateFilterCount = (properties) => {
|
|
6
|
+
const filterCount = {
|
|
7
|
+
propertyusegroup: {},
|
|
8
|
+
propertyusestandardized: {},
|
|
9
|
+
hvaccoolingdetail: {},
|
|
10
|
+
hvacheatingdetail: {},
|
|
11
|
+
utilitieswatersource: {},
|
|
12
|
+
flooringmaterialprimary: {},
|
|
13
|
+
};
|
|
14
|
+
properties.forEach(p => {
|
|
15
|
+
if (p.propertyusestandardized.toLowerCase() !== utils_1.UNKNOWN &&
|
|
16
|
+
p.propertyusegroup.toLowerCase() !== utils_1.UNKNOWN) {
|
|
17
|
+
const propertyUseKey = p.propertyusestandardized + utils_1.SEPARATOR_CHARACTER + p.propertyusegroup;
|
|
18
|
+
filterCount.propertyusestandardized[propertyUseKey] =
|
|
19
|
+
filterCount.propertyusestandardized[propertyUseKey] || 0;
|
|
20
|
+
filterCount.propertyusestandardized[propertyUseKey] += 1;
|
|
21
|
+
filterCount.propertyusegroup[p.propertyusegroup] =
|
|
22
|
+
filterCount.propertyusegroup[p.propertyusegroup] || 0;
|
|
23
|
+
filterCount.propertyusegroup[p.propertyusegroup] += 1;
|
|
24
|
+
}
|
|
25
|
+
if (p.hvaccoolingdetail.toLowerCase() !== utils_1.UNKNOWN) {
|
|
26
|
+
filterCount.hvaccoolingdetail[p.hvaccoolingdetail] =
|
|
27
|
+
filterCount.hvaccoolingdetail[p.hvaccoolingdetail] || 0;
|
|
28
|
+
filterCount.hvaccoolingdetail[p.hvaccoolingdetail] += 1;
|
|
29
|
+
}
|
|
30
|
+
if (p.hvacheatingdetail.toLowerCase() !== utils_1.UNKNOWN) {
|
|
31
|
+
filterCount.hvacheatingdetail[p.hvacheatingdetail] =
|
|
32
|
+
filterCount.hvacheatingdetail[p.hvacheatingdetail] || 0;
|
|
33
|
+
filterCount.hvacheatingdetail[p.hvacheatingdetail] += 1;
|
|
34
|
+
}
|
|
35
|
+
if (p.utilitieswatersource.toLowerCase() !== utils_1.UNKNOWN) {
|
|
36
|
+
filterCount.utilitieswatersource[p.utilitieswatersource] =
|
|
37
|
+
filterCount.utilitieswatersource[p.utilitieswatersource] || 0;
|
|
38
|
+
filterCount.utilitieswatersource[p.utilitieswatersource] += 1;
|
|
39
|
+
}
|
|
40
|
+
if (p.flooringmaterialprimary.toLowerCase() !== utils_1.UNKNOWN) {
|
|
41
|
+
filterCount.flooringmaterialprimary[p.flooringmaterialprimary] =
|
|
42
|
+
filterCount.flooringmaterialprimary[p.flooringmaterialprimary] || 0;
|
|
43
|
+
filterCount.flooringmaterialprimary[p.flooringmaterialprimary] += 1;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const propertyusegroupCounts = Object.keys(filterCount.propertyusegroup).map(name => ({
|
|
47
|
+
name,
|
|
48
|
+
count: filterCount.propertyusegroup[name],
|
|
49
|
+
}));
|
|
50
|
+
const propertyusestandardizedCounts = Object.keys(filterCount.propertyusestandardized).map(key => {
|
|
51
|
+
const [name, groupName] = key.split(utils_1.SEPARATOR_CHARACTER);
|
|
52
|
+
return {
|
|
53
|
+
name,
|
|
54
|
+
groupName,
|
|
55
|
+
count: filterCount.propertyusestandardized[key],
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
const hvaccoolingdetailCounts = Object.keys(filterCount.hvaccoolingdetail).map(name => ({
|
|
59
|
+
name,
|
|
60
|
+
count: filterCount.hvaccoolingdetail[name],
|
|
61
|
+
}));
|
|
62
|
+
const flooringmaterialprimaryCounts = Object.keys(filterCount.flooringmaterialprimary).map(name => ({
|
|
63
|
+
name,
|
|
64
|
+
count: filterCount.flooringmaterialprimary[name],
|
|
65
|
+
}));
|
|
66
|
+
const hvacheatingdetailCounts = Object.keys(filterCount.hvacheatingdetail).map(name => ({
|
|
67
|
+
name,
|
|
68
|
+
count: filterCount.hvacheatingdetail[name],
|
|
69
|
+
}));
|
|
70
|
+
const utilitieswatersourceCounts = Object.keys(filterCount.utilitieswatersource).map(name => ({
|
|
71
|
+
name,
|
|
72
|
+
count: filterCount.utilitieswatersource[name],
|
|
73
|
+
}));
|
|
74
|
+
return {
|
|
75
|
+
propertyusegroupCounts,
|
|
76
|
+
propertyusestandardizedCounts,
|
|
77
|
+
hvaccoolingdetailCounts,
|
|
78
|
+
hvacheatingdetailCounts,
|
|
79
|
+
utilitieswatersourceCounts,
|
|
80
|
+
flooringmaterialprimaryCounts,
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
exports.calculateFilterCount = calculateFilterCount;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFilterFetcherProcessor = void 0;
|
|
4
|
+
const calc_filter_count_1 = require("./calc-filter-count");
|
|
5
|
+
function getFilterFetcherProcessor(db) {
|
|
6
|
+
const getPropertiesCollection = async () => {
|
|
7
|
+
return db.collection('properties');
|
|
8
|
+
};
|
|
9
|
+
const getFiltersCollection = async () => {
|
|
10
|
+
return db.collection('filters');
|
|
11
|
+
};
|
|
12
|
+
const getProperties = async (zip) => {
|
|
13
|
+
const collection = await getPropertiesCollection();
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
collection
|
|
16
|
+
.find({ zipcode: zip }, {
|
|
17
|
+
projection: {
|
|
18
|
+
zipcode: 1,
|
|
19
|
+
propertyusegroup: 1,
|
|
20
|
+
propertyusestandardized: 1,
|
|
21
|
+
hvaccoolingdetail: 1,
|
|
22
|
+
hvacheatingdetail: 1,
|
|
23
|
+
utilitieswatersource: 1,
|
|
24
|
+
flooringmaterialprimary: 1,
|
|
25
|
+
_id: 0, // eslint-disable-line
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
.toArray((err, results) => {
|
|
29
|
+
if (err) {
|
|
30
|
+
return reject(err);
|
|
31
|
+
}
|
|
32
|
+
resolve(results);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
const deleteZipFilter = async (zip) => {
|
|
37
|
+
const collection = await getFiltersCollection();
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
collection.deleteOne({ zipcode: zip }, (err, results) => {
|
|
40
|
+
if (err) {
|
|
41
|
+
return reject(err);
|
|
42
|
+
}
|
|
43
|
+
resolve(results);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const addZipFilters = async ({ zip, propertyusegroupCounts, propertyusestandardizedCounts, hvaccoolingdetailCounts, hvacheatingdetailCounts, utilitieswatersourceCounts, flooringmaterialprimaryCounts, }) => {
|
|
48
|
+
const collection = await getFiltersCollection();
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
collection.insertOne({
|
|
51
|
+
zipcode: zip,
|
|
52
|
+
propertyusegroup: propertyusegroupCounts,
|
|
53
|
+
propertyusestandardized: propertyusestandardizedCounts,
|
|
54
|
+
hvaccoolingdetail: hvaccoolingdetailCounts,
|
|
55
|
+
hvacheatingdetail: hvacheatingdetailCounts,
|
|
56
|
+
utilitieswatersource: utilitieswatersourceCounts,
|
|
57
|
+
flooringmaterialprimary: flooringmaterialprimaryCounts,
|
|
58
|
+
}, (err, results) => {
|
|
59
|
+
if (err) {
|
|
60
|
+
return reject(err);
|
|
61
|
+
}
|
|
62
|
+
resolve(results);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
return async function processZip(zip, errors) {
|
|
67
|
+
if (!zip) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const properties = await getProperties(zip);
|
|
72
|
+
const filters = (0, calc_filter_count_1.calculateFilterCount)(properties);
|
|
73
|
+
await deleteZipFilter(zip);
|
|
74
|
+
await addZipFilters({
|
|
75
|
+
zip,
|
|
76
|
+
...filters,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
errors.add(zip);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
exports.getFilterFetcherProcessor = getFilterFetcherProcessor;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.propertyUseGroupProcessorAggregate = exports.getPropertyUseGroupProcessor = void 0;
|
|
4
|
+
const utils_1 = require("../utils/utils");
|
|
5
|
+
const getPropertiesCollection = async (db) => {
|
|
6
|
+
return db.collection('properties');
|
|
7
|
+
};
|
|
8
|
+
function fixPropertyName(propertyName) {
|
|
9
|
+
return propertyName ? propertyName.toUpperCase() : '';
|
|
10
|
+
}
|
|
11
|
+
function getPropertyUseGroupProcessor(db) {
|
|
12
|
+
const getProperties = async (zip) => {
|
|
13
|
+
const collection = await getPropertiesCollection(db);
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
collection
|
|
16
|
+
.find({ zipcode: zip }, {
|
|
17
|
+
projection: {
|
|
18
|
+
propertyusegroup: 1,
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
.toArray((err, results) => {
|
|
22
|
+
if (err) {
|
|
23
|
+
return reject(err);
|
|
24
|
+
}
|
|
25
|
+
resolve(results);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
function fixPropertyNames(properties) {
|
|
30
|
+
return properties
|
|
31
|
+
.filter(p => p.propertyusegroup &&
|
|
32
|
+
typeof p.propertyusegroup === 'string' &&
|
|
33
|
+
!(0, utils_1.isEmptyField)(p.propertyusegroup))
|
|
34
|
+
.map(p => {
|
|
35
|
+
return {
|
|
36
|
+
...p,
|
|
37
|
+
propertyusegroup: fixPropertyName(p.propertyusegroup),
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const updateProperties = async (properties) => {
|
|
42
|
+
const collection = await getPropertiesCollection(db);
|
|
43
|
+
const propQuery = properties.map(({ _id, ...p }) => ({
|
|
44
|
+
updateOne: {
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
46
|
+
filter: { _id },
|
|
47
|
+
update: { $set: p },
|
|
48
|
+
},
|
|
49
|
+
}));
|
|
50
|
+
return collection.bulkWrite(propQuery, { ordered: true, w: 1 });
|
|
51
|
+
};
|
|
52
|
+
return async function processZip(zip, errors) {
|
|
53
|
+
if (!zip) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const properties = await getProperties(zip);
|
|
58
|
+
if (!properties || !properties.length) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const convertedProperties = fixPropertyNames(properties);
|
|
62
|
+
if (!convertedProperties.length) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
await updateProperties(convertedProperties);
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
errors.add(zip);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
exports.getPropertyUseGroupProcessor = getPropertyUseGroupProcessor;
|
|
73
|
+
async function propertyUseGroupProcessorAggregate(db) {
|
|
74
|
+
const collection = await getPropertiesCollection(db);
|
|
75
|
+
const aggCursor = await collection.aggregate([
|
|
76
|
+
{
|
|
77
|
+
$set: {
|
|
78
|
+
propertyusegroup: {
|
|
79
|
+
$function: {
|
|
80
|
+
body: fixPropertyName.toString(),
|
|
81
|
+
args: ['$propertyusegroup'],
|
|
82
|
+
lang: 'js',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
$merge: {
|
|
89
|
+
into: 'properties',
|
|
90
|
+
on: '_id',
|
|
91
|
+
whenMatched: 'replace',
|
|
92
|
+
whenNotMatched: 'insert',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
]);
|
|
96
|
+
let result;
|
|
97
|
+
do {
|
|
98
|
+
result = await aggCursor.next(); // eslint-disable-line no-await-in-loop
|
|
99
|
+
} while (result);
|
|
100
|
+
}
|
|
101
|
+
exports.propertyUseGroupProcessorAggregate = propertyUseGroupProcessorAggregate;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.propertiesAssessorLastSaleDateAggregate = exports.propertyUseGroupProcessorAggregate = exports.configureProcessor = void 0;
|
|
4
|
+
const filter_fetcher_1 = require("./filter-fetcher");
|
|
5
|
+
const fix_property_use_1 = require("./fix-property-use");
|
|
6
|
+
const property_assessorlastsaledate_converter_1 = require("./property-assessorlastsaledate-converter");
|
|
7
|
+
const zip_processor_1 = require("./zip-processor");
|
|
8
|
+
function configureProcessor(config) {
|
|
9
|
+
const filterFetcher = (0, zip_processor_1.zipProcessor)(config, (0, filter_fetcher_1.getFilterFetcherProcessor)(config.mongoDb));
|
|
10
|
+
const assessorLastSaleDateProcessor = (0, zip_processor_1.zipProcessor)(config, (0, property_assessorlastsaledate_converter_1.getAssessorLastSaleDateProcessor)(config.mongoDb));
|
|
11
|
+
const propertyUseGroupProcessor = (0, zip_processor_1.zipProcessor)(config, (0, fix_property_use_1.getPropertyUseGroupProcessor)(config.mongoDb));
|
|
12
|
+
return { filterFetcher, assessorLastSaleDateProcessor, propertyUseGroupProcessor };
|
|
13
|
+
}
|
|
14
|
+
exports.configureProcessor = configureProcessor;
|
|
15
|
+
var fix_property_use_2 = require("./fix-property-use");
|
|
16
|
+
Object.defineProperty(exports, "propertyUseGroupProcessorAggregate", { enumerable: true, get: function () { return fix_property_use_2.propertyUseGroupProcessorAggregate; } });
|
|
17
|
+
var property_assessorlastsaledate_converter_2 = require("./property-assessorlastsaledate-converter");
|
|
18
|
+
Object.defineProperty(exports, "propertiesAssessorLastSaleDateAggregate", { enumerable: true, get: function () { return property_assessorlastsaledate_converter_2.propertiesAssessorLastSaleDateAggregate; } });
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.propertiesAssessorLastSaleDateAggregate = exports.getAssessorLastSaleDateProcessor = void 0;
|
|
4
|
+
const utils_1 = require("../utils/utils");
|
|
5
|
+
const getPropertiesCollection = async (db) => {
|
|
6
|
+
return db.collection('properties');
|
|
7
|
+
};
|
|
8
|
+
function getAssessorLastSaleDateProcessor(db) {
|
|
9
|
+
const getPropertiesAssessorLastSaleDate = async (zip) => {
|
|
10
|
+
const collection = await getPropertiesCollection(db);
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
collection
|
|
13
|
+
.find({
|
|
14
|
+
zipcode: zip,
|
|
15
|
+
assessorlastsaledate: {
|
|
16
|
+
$exists: true,
|
|
17
|
+
$type: 2,
|
|
18
|
+
},
|
|
19
|
+
}, {
|
|
20
|
+
projection: {
|
|
21
|
+
assessorlastsaledate: 1,
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
.toArray((err, results) => {
|
|
25
|
+
if (err) {
|
|
26
|
+
return reject(err);
|
|
27
|
+
}
|
|
28
|
+
resolve(results);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
const updateProperties = async (properties) => {
|
|
33
|
+
const collection = await getPropertiesCollection(db);
|
|
34
|
+
const propQuery = properties.map(({ _id, ...p }) => ({
|
|
35
|
+
updateOne: {
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
37
|
+
filter: { _id },
|
|
38
|
+
update: { $set: p },
|
|
39
|
+
},
|
|
40
|
+
}));
|
|
41
|
+
return collection.bulkWrite(propQuery, { ordered: true, w: 1 });
|
|
42
|
+
};
|
|
43
|
+
return async function processZip(zip, errors) {
|
|
44
|
+
if (!zip) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const properties = await getPropertiesAssessorLastSaleDate(zip);
|
|
49
|
+
if (!properties || !properties.length) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const convertedProperties = (0, utils_1.convertStringToDate)(properties, 'assessorlastsaledate');
|
|
53
|
+
if (!convertedProperties.length) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
await updateProperties(convertedProperties);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
errors.add(zip);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
exports.getAssessorLastSaleDateProcessor = getAssessorLastSaleDateProcessor;
|
|
64
|
+
async function propertiesAssessorLastSaleDateAggregate(db) {
|
|
65
|
+
const collection = await getPropertiesCollection(db);
|
|
66
|
+
const aggCursor = collection.aggregate([
|
|
67
|
+
{
|
|
68
|
+
$match: {
|
|
69
|
+
assessorlastsaledate: {
|
|
70
|
+
$exists: true,
|
|
71
|
+
$type: 2,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
$set: {
|
|
77
|
+
assessorlastsaledate: {
|
|
78
|
+
$function: {
|
|
79
|
+
body: `function (d) {
|
|
80
|
+
return new Date(d);
|
|
81
|
+
}`,
|
|
82
|
+
args: ['$assessorlastsaledate'],
|
|
83
|
+
lang: 'js',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
$merge: {
|
|
90
|
+
into: 'properties',
|
|
91
|
+
on: '_id',
|
|
92
|
+
whenMatched: 'replace',
|
|
93
|
+
whenNotMatched: 'insert',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
]);
|
|
97
|
+
let result;
|
|
98
|
+
do {
|
|
99
|
+
result = await aggCursor.next(); // eslint-disable-line no-await-in-loop
|
|
100
|
+
} while (result);
|
|
101
|
+
}
|
|
102
|
+
exports.propertiesAssessorLastSaleDateAggregate = propertiesAssessorLastSaleDateAggregate;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertStringToDate = exports.convertToZipString = exports.convertObjectToArray = exports.extractUniqueFilterNames = exports.isEmptyField = exports.isNotFullProperty = exports.UNKNOWN = exports.SEPARATOR_CHARACTER = void 0;
|
|
4
|
+
exports.SEPARATOR_CHARACTER = '___';
|
|
5
|
+
exports.UNKNOWN = 'unknown';
|
|
6
|
+
const isNotFullProperty = (property) => {
|
|
7
|
+
if (!property.hvaccoolingdetail) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
return ((0, exports.isEmptyField)(property.hvaccoolingdetail) ||
|
|
11
|
+
(0, exports.isEmptyField)(property.hvacheatingdetail) ||
|
|
12
|
+
(0, exports.isEmptyField)(property.utilitieswatersource) ||
|
|
13
|
+
(0, exports.isEmptyField)(property.propertyusegroup) ||
|
|
14
|
+
(0, exports.isEmptyField)(property.propertyusestandardized) ||
|
|
15
|
+
(0, exports.isEmptyField)(property.flooringmaterialprimary));
|
|
16
|
+
};
|
|
17
|
+
exports.isNotFullProperty = isNotFullProperty;
|
|
18
|
+
const isEmptyField = (field) => {
|
|
19
|
+
return field.toLowerCase() === exports.UNKNOWN;
|
|
20
|
+
};
|
|
21
|
+
exports.isEmptyField = isEmptyField;
|
|
22
|
+
const extractUniqueFilterNames = (properties) => {
|
|
23
|
+
const hvaccoolingdetail = new Set();
|
|
24
|
+
const hvacheatingdetail = new Set();
|
|
25
|
+
const utilitieswatersource = new Set();
|
|
26
|
+
const propertyusegroup = new Set();
|
|
27
|
+
const propertyusestandardized = new Set();
|
|
28
|
+
const flooringmaterialprimary = new Set();
|
|
29
|
+
properties.forEach(property => {
|
|
30
|
+
hvaccoolingdetail.add(property.hvaccoolingdetail);
|
|
31
|
+
hvacheatingdetail.add(property.hvacheatingdetail);
|
|
32
|
+
propertyusegroup.add(property.propertyusegroup);
|
|
33
|
+
utilitieswatersource.add(property.utilitieswatersource);
|
|
34
|
+
propertyusestandardized.add(property.propertyusestandardized + exports.SEPARATOR_CHARACTER + property.propertyusegroup);
|
|
35
|
+
flooringmaterialprimary.add(property.flooringmaterialprimary);
|
|
36
|
+
});
|
|
37
|
+
const propertyUseObjects = Array.from(propertyusestandardized).map(filter => {
|
|
38
|
+
const split = filter.split(exports.SEPARATOR_CHARACTER);
|
|
39
|
+
return {
|
|
40
|
+
name: split[0],
|
|
41
|
+
typeName: split[1],
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
const hvacCoolingSystemNames = Array.from(hvaccoolingdetail);
|
|
45
|
+
const hvacHeatingSystemNames = Array.from(hvacheatingdetail);
|
|
46
|
+
const propertyTypeNames = Array.from(propertyusegroup);
|
|
47
|
+
const waterSourceNames = Array.from(utilitieswatersource);
|
|
48
|
+
const flooringMaterialsNames = Array.from(flooringmaterialprimary);
|
|
49
|
+
return {
|
|
50
|
+
propertyUseObjects,
|
|
51
|
+
propertyTypeNames,
|
|
52
|
+
hvacCoolingSystemNames,
|
|
53
|
+
hvacHeatingSystemNames,
|
|
54
|
+
waterSourceNames,
|
|
55
|
+
flooringMaterialsNames,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
exports.extractUniqueFilterNames = extractUniqueFilterNames;
|
|
59
|
+
const convertObjectToArray = (obj) => {
|
|
60
|
+
const array = [];
|
|
61
|
+
for (const key in obj) {
|
|
62
|
+
array.push(obj[key]);
|
|
63
|
+
}
|
|
64
|
+
return array;
|
|
65
|
+
};
|
|
66
|
+
exports.convertObjectToArray = convertObjectToArray;
|
|
67
|
+
const ZIP_STRING_LENGTH = 5;
|
|
68
|
+
const convertToZipString = (zipNumber) => {
|
|
69
|
+
const zipString = zipNumber + '';
|
|
70
|
+
return zipString.padStart(ZIP_STRING_LENGTH, '0');
|
|
71
|
+
};
|
|
72
|
+
exports.convertToZipString = convertToZipString;
|
|
73
|
+
const convertStringToDate = (props, propName) => {
|
|
74
|
+
return props
|
|
75
|
+
.filter(p => p[propName] &&
|
|
76
|
+
typeof p[propName] === 'string' &&
|
|
77
|
+
!(0, exports.isEmptyField)(p[propName]))
|
|
78
|
+
.map(p => ({ ...p, [propName]: new Date(p[propName]) }));
|
|
79
|
+
};
|
|
80
|
+
exports.convertStringToDate = convertStringToDate;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable no-await-in-loop, require-atomic-updates */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.zipProcessor = void 0;
|
|
5
|
+
const utils_1 = require("./utils/utils");
|
|
6
|
+
function zipProcessor(config, processorFn) {
|
|
7
|
+
let processor = null;
|
|
8
|
+
let erroredZips = new Set();
|
|
9
|
+
async function* processZips(zips) {
|
|
10
|
+
if (!zips) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
// eslint-disable-next-line prefer-const
|
|
14
|
+
let [startZipNum, endZipNum] = zips.split('-').map(Number);
|
|
15
|
+
if (!endZipNum) {
|
|
16
|
+
endZipNum = startZipNum;
|
|
17
|
+
}
|
|
18
|
+
for (let zipNum = startZipNum; zipNum <= endZipNum;) {
|
|
19
|
+
const processes = [];
|
|
20
|
+
const processZipEnd = zipNum + config.workers - 1;
|
|
21
|
+
for (; zipNum <= endZipNum && zipNum <= processZipEnd; zipNum++) {
|
|
22
|
+
const zip = (0, utils_1.convertToZipString)(zipNum);
|
|
23
|
+
processes.push(processorFn(zip, erroredZips));
|
|
24
|
+
}
|
|
25
|
+
yield await Promise.all(processes);
|
|
26
|
+
}
|
|
27
|
+
while (erroredZips.size) {
|
|
28
|
+
const connectionErrorZipsInner = [...erroredZips];
|
|
29
|
+
erroredZips = new Set();
|
|
30
|
+
for (let i = 0; i <= connectionErrorZipsInner.length; i++) {
|
|
31
|
+
const zip = connectionErrorZipsInner[i];
|
|
32
|
+
yield await processorFn(zip, erroredZips);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function clear() {
|
|
37
|
+
if (processor) {
|
|
38
|
+
await processor.return();
|
|
39
|
+
}
|
|
40
|
+
processor = null;
|
|
41
|
+
}
|
|
42
|
+
async function start(zips) {
|
|
43
|
+
processor = processZips(zips);
|
|
44
|
+
try {
|
|
45
|
+
let step = await processor.next();
|
|
46
|
+
while (processor && !step.done) {
|
|
47
|
+
step = await processor.next();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
await clear();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
getProcessor: () => processor,
|
|
56
|
+
start,
|
|
57
|
+
clear,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
exports.zipProcessor = zipProcessor;
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@servicetitan/acquisition-functions",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"typings": "./dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p .",
|
|
9
|
+
"test": "jest --runInBand"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@jest/globals": "29.1.2",
|
|
16
|
+
"@tsconfig/node16": "^1.0.3",
|
|
17
|
+
"@types/jest": "^29.1.0",
|
|
18
|
+
"@types/mongodb": "^3.6.20",
|
|
19
|
+
"@types/node": "^18.6.3",
|
|
20
|
+
"jest": "29.1.2",
|
|
21
|
+
"mongodb": "3.6.3",
|
|
22
|
+
"ts-jest": "29.0.3",
|
|
23
|
+
"ts-node": "^10.9.1"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"cli": {
|
|
29
|
+
"webpack": false
|
|
30
|
+
},
|
|
31
|
+
"gitHead": "30de32ace907277b336c7bc835e659b2a3ffaac9"
|
|
32
|
+
}
|