@engine9/schemas 1.9.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.
Files changed (122) hide show
  1. package/.eslintignore +1 -0
  2. package/.prettierrc +7 -0
  3. package/AGENTS.md +10 -0
  4. package/LICENSE +21 -0
  5. package/README.md +33 -0
  6. package/channels/email/README.md +83 -0
  7. package/channels/email/index.js +22 -0
  8. package/channels/email/search.js +86 -0
  9. package/channels/email/segments.js +81 -0
  10. package/eslint.config.js +21 -0
  11. package/event/README.md +79 -0
  12. package/event/index.js +17 -0
  13. package/event/schema.js +111 -0
  14. package/event/search.js +51 -0
  15. package/message/index.js +8 -0
  16. package/message/schema.js +130 -0
  17. package/message/ui.console.json5 +233 -0
  18. package/package.json +26 -0
  19. package/person/index.js +100 -0
  20. package/person/metrics.js +17 -0
  21. package/person/schema.js +47 -0
  22. package/person/transforms/inbound/normalize_field_names.js +16 -0
  23. package/person/transforms/inbound/upsert_tables.js +21 -0
  24. package/person/transforms/outbound/appendName.js +32 -0
  25. package/person/transforms/simpleMap.js +34 -0
  26. package/person/ui.console.json5 +165 -0
  27. package/person/upsert.test.js +72 -0
  28. package/person_address/index.js +30 -0
  29. package/person_address/normalize.js +232 -0
  30. package/person_address/normalize.test.js +69 -0
  31. package/person_address/schema.js +49 -0
  32. package/person_address/transforms/inbound/normalize.js +23 -0
  33. package/person_address/transforms/inbound/upsert_tables.js +51 -0
  34. package/person_address/transforms/outbound/appendAddress.js +87 -0
  35. package/person_address/ui.console.json5 +31 -0
  36. package/person_custom/index.js +24 -0
  37. package/person_custom/transforms/appendRemoteId.js +31 -0
  38. package/person_custom/transforms/inbound/upsert_tables.js +31 -0
  39. package/person_email/README.md +82 -0
  40. package/person_email/index.js +35 -0
  41. package/person_email/schema.js +49 -0
  42. package/person_email/search.js +61 -0
  43. package/person_email/segments.js +16 -0
  44. package/person_email/transforms/inbound/extract_identifiers.js +33 -0
  45. package/person_email/transforms/inbound/upsert_tables.js +142 -0
  46. package/person_email/transforms/outbound/appendEmail.js +32 -0
  47. package/person_email/transforms/outbound/appendEmailHash.js +20 -0
  48. package/person_email/transforms/outbound/tables.js +14 -0
  49. package/person_email/ui.console.json5 +58 -0
  50. package/person_email/upsert.test.js +126 -0
  51. package/person_hash/README.md +70 -0
  52. package/person_hash/hash.js +103 -0
  53. package/person_hash/hash.test.js +165 -0
  54. package/person_hash/index.js +37 -0
  55. package/person_hash/schema.js +54 -0
  56. package/person_hash/search.js +86 -0
  57. package/person_hash/transforms/inbound/extract_identifiers.js +70 -0
  58. package/person_hash/transforms/inbound/upsert_tables.js +105 -0
  59. package/person_hash/transforms/outbound/appendEmailHash.js +42 -0
  60. package/person_hash/transforms/outbound/appendPhoneHash.js +42 -0
  61. package/person_hash/ui.console.json5 +80 -0
  62. package/person_phone/README.md +79 -0
  63. package/person_phone/index.js +33 -0
  64. package/person_phone/schema.js +58 -0
  65. package/person_phone/search.js +79 -0
  66. package/person_phone/segments.js +26 -0
  67. package/person_phone/transforms/inbound/extract_identifiers.js +59 -0
  68. package/person_phone/transforms/inbound/upsert_tables.js +119 -0
  69. package/person_phone/transforms/outbound/appendPhoneHash.js +37 -0
  70. package/person_phone/ui.console.json5 +31 -0
  71. package/person_phone/upsert.test.js +50 -0
  72. package/person_remote/index.js +58 -0
  73. package/person_remote/metrics.js +17 -0
  74. package/person_remote/schema.js +21 -0
  75. package/person_remote/transforms/inbound/extract_identifiers.js +34 -0
  76. package/person_remote/transforms/inbound/upsert_tables.js +92 -0
  77. package/person_remote/transforms/outbound/appendRemotePersonId.js +59 -0
  78. package/plugin/index.js +13 -0
  79. package/plugin/schema.js +70 -0
  80. package/plugin/settings.js +19 -0
  81. package/plugin/ui.console.json5 +79 -0
  82. package/report/index.js +7 -0
  83. package/report/ui.console.json5 +21 -0
  84. package/segment/index.js +21 -0
  85. package/segment/schema.js +81 -0
  86. package/segment/search.js +64 -0
  87. package/segment/transforms/inbound/upsert.js +44 -0
  88. package/segment/ui.console.json5 +142 -0
  89. package/segment_stats/index.js +16 -0
  90. package/segment_stats/schema.js +30 -0
  91. package/source_code/index.js +16 -0
  92. package/source_code/metrics.js +28 -0
  93. package/source_code/schema.js +29 -0
  94. package/source_code/ui.console.json5 +31 -0
  95. package/stacks/limited-pii/index.js +8 -0
  96. package/stacks/limited-pii/stack.json +22 -0
  97. package/stacks/stacks.test.js +27 -0
  98. package/stacks/standard/index.js +7 -0
  99. package/stacks/standard/stack.json +20 -0
  100. package/tag/index.js +13 -0
  101. package/tag/schema.js +23 -0
  102. package/task/index.js +13 -0
  103. package/task/schema.js +54 -0
  104. package/task/ui.console.json5 +60 -0
  105. package/timeline/index.js +18 -0
  106. package/timeline/schema.js +18 -0
  107. package/timeline/transforms/inbound/upsert_tables.js +22 -0
  108. package/timeline/ui.console.json5 +31 -0
  109. package/transaction/contact_details/index.js +11 -0
  110. package/transaction/contact_details/schema.js +22 -0
  111. package/transaction/core/README.md +79 -0
  112. package/transaction/core/attribute.test.js +231 -0
  113. package/transaction/core/index.js +31 -0
  114. package/transaction/core/metrics.js +20 -0
  115. package/transaction/core/schema.js +45 -0
  116. package/transaction/core/search.js +87 -0
  117. package/transaction/core/segments.js +14 -0
  118. package/transaction/core/transforms/appendTransactionSummary.js +101 -0
  119. package/transaction/core/transforms/attribute.js +327 -0
  120. package/transaction/core/transforms/inbound/upsert_tables.js +57 -0
  121. package/utilities/limited-pii/index.js +14 -0
  122. package/utilities/limited-pii/settings.js +12 -0
@@ -0,0 +1,70 @@
1
+ export const tables = [
2
+ {
3
+ name: 'plugin',
4
+ columns: {
5
+ id: 'id_uuid',
6
+ path: 'string',
7
+ name: 'string',
8
+ nickname: 'string',
9
+ table_prefix: 'string',
10
+ remote_plugin_id: 'string',
11
+ schema: 'json', // Not all plugins need to support file based schemas, like per-account custom fields
12
+ transforms: 'json', // Not all plugins need to support file based transforms, like per-account custom fields
13
+ created_at: 'created_at',
14
+ modified_at: 'modified_at'
15
+ },
16
+ indexes: [
17
+ { columns: 'id', primary: true },
18
+ { columns: 'remote_plugin_id', unique: true }
19
+ ]
20
+ },
21
+ {
22
+ name: 'plugin_history',
23
+ columns: {
24
+ id: 'id_uuid',
25
+ plugin_id: 'id_uuid', // can't be null, must have a value
26
+ path: 'string',
27
+ created_at: 'created_at',
28
+ modified_at: 'modified_at'
29
+ },
30
+ indexes: [{ columns: 'id', primary: true }]
31
+ },
32
+ {
33
+ name: 'setting',
34
+ columns: {
35
+ id: 'id_uuid',
36
+ plugin_id: 'foreign_uuid',
37
+ name: 'string',
38
+ value: 'string',
39
+ created_at: 'created_at',
40
+ modified_at: 'modified_at'
41
+ },
42
+ indexes: [
43
+ { columns: 'id', primary: true },
44
+ { columns: 'plugin_id,name', unique: true }
45
+ ]
46
+ },
47
+ {
48
+ name: 'input',
49
+ columns: {
50
+ id: 'id_uuid',
51
+ plugin_id: 'id_uuid', // can't be null, must have a value
52
+ remote_input_id: 'string', // The remote id for this input, unique across the plugin
53
+ remote_input_name: 'string', // The remote name -- a human name for this input -- e.g. Form Name, message name
54
+ input_type: 'string', // Type of input, e.g. message, remote_person, petition, signup_form, advocacy_action, etc
55
+ min_timeline_ts: 'datetime',
56
+ max_timeline_ts: 'datetime',
57
+ records: 'bigint', // total timeline records across idv1.parquet files in the input store
58
+ data_path: 'string', // where the source data lives for this input, a directory or a packet
59
+ created_at: 'created_at',
60
+ modified_at: 'modified_at'
61
+ },
62
+ indexes: [
63
+ { columns: 'id', primary: true },
64
+ { columns: 'plugin_id,remote_input_id', unique: true }
65
+ ]
66
+ }
67
+ ];
68
+ export default {
69
+ tables
70
+ };
@@ -0,0 +1,19 @@
1
+ export const settings = [
2
+ {
3
+ name: 'table_prefix_counter',
4
+ type: 'int',
5
+ default: 2729,
6
+ hidden: true,
7
+ description: 'Hex table-prefix allocator. Incremented by PluginWorker.getNextTablePrefixCounter.'
8
+ },
9
+ {
10
+ name: 'default_stack',
11
+ type: 'string',
12
+ default: '',
13
+ description:
14
+ 'Stack (or plugin) path for installDefaultPlugins when no path is passed — e.g. @engine9/schemas/stacks/standard or @engine9/schemas/stacks/limited-pii. Empty installs the core person schema plugins only. Ignored when @engine9/schemas/utilities/limited-pii has exclude_pii true (forced limited-pii stack).'
15
+ }
16
+ ];
17
+ export default {
18
+ settings
19
+ };
@@ -0,0 +1,79 @@
1
+ {
2
+ menu: {
3
+ settings: {
4
+ children: {
5
+ queries: {
6
+ title: 'Plugins',
7
+ icon: 'plugins',
8
+ url: '/plugins'
9
+ }
10
+ }
11
+ }
12
+ },
13
+ routes: {
14
+ plugins: {
15
+ layout: 'full_width',
16
+ components: {
17
+ header: ['Plugins'],
18
+ main: [
19
+ {
20
+ component: 'RecordTable',
21
+ properties: {
22
+ table: 'plugin',
23
+ columns: [
24
+ {
25
+ title: 'Id',
26
+ dataIndex: 'id',
27
+ sorter: true,
28
+ width: '20%'
29
+ },
30
+ {
31
+ title: 'Name',
32
+ dataIndex: 'name',
33
+ sorter: true,
34
+ template: '{{name}}',
35
+ width: '40%'
36
+ }
37
+ ],
38
+ onRecord: {
39
+ onClick: {
40
+ action: 'navigate',
41
+ url: '/plugins/{{record.id}}'
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ]
47
+ }
48
+ },
49
+ 'plugins/:id/*': {
50
+ layout: 'full_width',
51
+ components: {
52
+ main: [
53
+ {
54
+ component: 'RecordForm',
55
+ properties: {
56
+ table: 'job',
57
+ title: '{{#if record.id}}Edit Plugin{{else}}Create Job{{/if}}',
58
+ form: {
59
+ type: 'object',
60
+ required: [],
61
+ properties: {
62
+ status: { type: 'string', title: 'Status', default: 'pending' },
63
+ options: { type: 'string', title: 'Options', default: '{}' }
64
+ }
65
+ },
66
+ uiSchema: {
67
+ options: { 'ui:widget': 'textarea' }
68
+ },
69
+ onSave: {
70
+ action: 'navigate',
71
+ url: '/plugins/{{record.id}}'
72
+ }
73
+ }
74
+ }
75
+ ]
76
+ }
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,7 @@
1
+ const metadata = {
2
+ name: '@engine9/schemas/report',
3
+ };
4
+ export { metadata };
5
+ export default {
6
+ metadata
7
+ };
@@ -0,0 +1,21 @@
1
+ {
2
+ menu: {
3
+ 'data-menu': {
4
+ children: {
5
+ report: {
6
+ title: 'Reports',
7
+ icon: 'report',
8
+ url: '/report'
9
+ }
10
+ }
11
+ }
12
+ },
13
+ routes: {
14
+ '/report': {
15
+ layout: 'full_width',
16
+ components: {
17
+ main: ['<h1>Reports</h1>']
18
+ }
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ import schema from './schema.js';
2
+ import search from './search.js';
3
+ import upsert from './transforms/inbound/upsert.js';
4
+ const metadata = {
5
+ name: '@engine9/schemas/segment',
6
+ dependencies: {
7
+ '@engine9/schemas/person': '>=1.9.0'
8
+ }
9
+ };
10
+ export const transforms = {
11
+ upsert
12
+ };
13
+ export { metadata };
14
+ export { schema };
15
+ export { search };
16
+ export default {
17
+ metadata,
18
+ schema,
19
+ search,
20
+ transforms
21
+ };
@@ -0,0 +1,81 @@
1
+ export const tables = [
2
+ {
3
+ name: 'segment_folder',
4
+ columns: {
5
+ id: 'id_uuid',
6
+ name: 'string',
7
+ description: 'text',
8
+ created_at: 'created_at',
9
+ modified_at: 'modified_at'
10
+ },
11
+ indexes: [{ columns: 'id', primary: true }]
12
+ },
13
+ {
14
+ name: 'segment',
15
+ columns: {
16
+ id: 'id_uuid',
17
+ plugin_id: 'id_uuid', // can't be null, must have a value
18
+ submodule: 'string',
19
+ segment_folder_id: 'foreign_uuid',
20
+ remote_segment_id: 'string',
21
+ legacy_id: 'int',
22
+ name: 'string',
23
+ category: 'string', // A arbitrary type, user facing, not to be used for logic
24
+ definition_path: 'string', // a definition file path, will be used for configuring
25
+ stars: 'int', //number of stars, good for UI organizing
26
+ search: 'json',
27
+ build_type: {
28
+ type: 'enum',
29
+ nullable: false,
30
+ default_value: 'list',
31
+ values: [
32
+ 'list', //static list of people
33
+ 'search', // built by the defined search
34
+ 'scheduled_search', // built on a schedule by the search
35
+ 'remote_count', // no person records, just counts, pulled from remote site
36
+ 'remote', // pulled from remote plugin site
37
+ 'manual' // created outside normal processing
38
+ ]
39
+ },
40
+ build_schedule: 'string',
41
+ build_status: 'string',
42
+ build_status_modified_at: 'modified_at',
43
+ build_table: 'string',
44
+ last_built: 'datetime',
45
+ // Membership policy. null = only a request with `admin` scope.
46
+ // join_min_level: lowest Identity Level at which a person may add
47
+ // themselves (0 = a public form, no login)
48
+ // leave_min_level: lowest Identity Level at which a person may remove
49
+ // themselves (never 0)
50
+ // manager_role_id: role segment whose members may add and remove
51
+ // other people in this segment
52
+ // Enforced by @engine9/core (docs/segments.md), not by the database.
53
+ join_min_level: { type: 'int', nullable: true },
54
+ leave_min_level: { type: 'int', nullable: true },
55
+ manager_role_id: 'foreign_uuid',
56
+ people: 'int', // engine9 count
57
+ reported_people: 'int', // reported by outside parties
58
+ created_at: 'created_at',
59
+ modified_at: 'modified_at'
60
+ },
61
+ indexes: [
62
+ { columns: 'id', primary: true },
63
+ // if there is a remote_segment_id, it should be unique for the plugin
64
+ { columns: ['plugin_id', 'remote_segment_id'], unique: true }
65
+ ]
66
+ },
67
+ // Used for some smaller segments, and a cache of segments
68
+ {
69
+ name: 'person_segment',
70
+ columns: {
71
+ id: 'id',
72
+ person_id: 'person_id',
73
+ segment_id: 'foreign_uuid',
74
+ modified_at: 'modified_at'
75
+ },
76
+ indexes: [{ columns: 'segment_id,person_id', unique: true }, { columns: 'person_id' }]
77
+ }
78
+ ];
79
+ export default {
80
+ tables
81
+ };
@@ -0,0 +1,64 @@
1
+ export const segment = {
2
+ title: 'Segment',
3
+ form: {
4
+ title: 'Segment',
5
+ type: 'object',
6
+ properties: {
7
+ segmentId: {
8
+ title: 'Segment',
9
+ description: '',
10
+ type: 'string'
11
+ }
12
+ },
13
+ required: []
14
+ },
15
+ optionsToEQLContext: function ({ segmentId }) {
16
+ return {
17
+ segments: {
18
+ table: 'segment',
19
+ columns: ['id', 'name'],
20
+ conditions: [
21
+ {
22
+ type: 'EQUALS',
23
+ values: [
24
+ {
25
+ ref: { column: 'id' }
26
+ },
27
+ {
28
+ value: { value: segmentId }
29
+ }
30
+ ]
31
+ }
32
+ ]
33
+ }
34
+ };
35
+ },
36
+ /* map from provided user data into an EQL structure */
37
+ optionsToEQL(options, { segments } = {}) {
38
+ const { segmentId } = options;
39
+ const segment = segments.find(({ id }) => id == segmentId);
40
+ if (!segment) throw new Error('Could not find segment ' + segmentId + ' in ' + segments.length + ' segments');
41
+ let text = 'In ' + segment.name || segmentId;
42
+ const conditions = [
43
+ {
44
+ type: 'EQUALS',
45
+ values: [
46
+ {
47
+ ref: { column: 'segment_id' }
48
+ },
49
+ {
50
+ value: { value: segmentId }
51
+ }
52
+ ]
53
+ }
54
+ ];
55
+ const eql = {
56
+ table: 'person_segment',
57
+ conditions
58
+ };
59
+ return { text, eql };
60
+ }
61
+ };
62
+ export default {
63
+ segment
64
+ };
@@ -0,0 +1,44 @@
1
+ import { mergeIntoQueue } from '@engine9/input-tools';
2
+
3
+ export const bindings = {
4
+ tablesToUpsert: { path: 'sql.tables.upsert' },
5
+ uuidIsValid: { path: '@engine9/input-tools:uuidIsValid' }
6
+ };
7
+ export async function transform({ batch, tablesToUpsert, uuidIsValid, options }) {
8
+ const { segmentIds } = options;
9
+ const globalSegments = String(segmentIds || '')
10
+ .split(',')
11
+ .map((d) => d.trim())
12
+ .filter(Boolean);
13
+ batch.forEach((o) => {
14
+ const localSegmentIds = String(o.segment_ids || '')
15
+ .split(',')
16
+ .map((d) => d.trim())
17
+ .filter(Boolean);
18
+ const allSegmentIds = [].concat(globalSegments).concat(localSegmentIds);
19
+ if (allSegmentIds.length === 0) return;
20
+ const invalid = allSegmentIds.filter((uuid) => !uuidIsValid(uuid));
21
+ if (invalid.length > 0) throw new Error(`There are some invalid segment_ids:${invalid.join(',')}`);
22
+ tablesToUpsert.person_segment = tablesToUpsert.person_segment || [];
23
+ allSegmentIds.forEach((sid) =>
24
+ mergeIntoQueue(
25
+ tablesToUpsert.person_segment,
26
+ {
27
+ id: null,
28
+ person_id: o.person_id,
29
+ segment_id: sid
30
+ },
31
+ {
32
+ keyFields: ['segment_id', 'person_id'],
33
+ merge: (existing) => existing,
34
+ label: 'person_segment'
35
+ }
36
+ )
37
+ );
38
+ });
39
+ return batch;
40
+ }
41
+ export default {
42
+ bindings,
43
+ transform
44
+ };
@@ -0,0 +1,142 @@
1
+ {
2
+ menu: {
3
+ people: {
4
+ children: {
5
+ segments: {
6
+ title: 'Segments',
7
+ icon: 'people',
8
+ url: '/segments'
9
+ }
10
+ }
11
+ }
12
+ },
13
+ routes: {
14
+ '/segments': {
15
+ layout: 'full_width',
16
+ components: {
17
+ header: [
18
+ 'Segments',
19
+ {
20
+ component: 'Button',
21
+ properties: {
22
+ icon: 'plus',
23
+ content: 'Add Segment',
24
+ onClick: {
25
+ action: 'navigate',
26
+ url: '/segments/create'
27
+ }
28
+ }
29
+ }
30
+ ],
31
+ main: [
32
+ {
33
+ component: 'RecordTable',
34
+ properties: {
35
+ table: 'segment',
36
+ columns: [
37
+ {
38
+ title: 'Id',
39
+ dataIndex: 'id',
40
+ sorter: true,
41
+ width: '20%'
42
+ },
43
+ {
44
+ title: 'Type',
45
+ dataIndex: 'type',
46
+ sorter: true
47
+ },
48
+ {
49
+ title: 'Name',
50
+ dataIndex: 'label',
51
+ sorter: true,
52
+ template: '{{label}}',
53
+ width: '40%'
54
+ }
55
+ ],
56
+ onRecord: {
57
+ onClick: {
58
+ action: 'navigate',
59
+ url: '/segments/{{record.id}}'
60
+ }
61
+ }
62
+ }
63
+ }
64
+ ]
65
+ }
66
+ },
67
+ '/segments/:id/*': {
68
+ layout: 'full_width',
69
+ components: {
70
+ main: [
71
+ {
72
+ component: 'RecordForm',
73
+ properties: {
74
+ table: 'job',
75
+ title: '{{#if record.id}}Edit Segment{{else}}Create Segment{{/if}}',
76
+ form: {
77
+ type: 'object',
78
+ required: [],
79
+ properties: {
80
+ type: { type: 'string', title: 'Type' },
81
+ name: { type: 'string', title: 'Name' },
82
+ plugin_id: { type: 'string', title: 'Source Plugin ID' },
83
+ remote_segment_id: { type: 'string', title: 'Remote Segment ID' },
84
+ build_mechanism: { type: 'string', title: 'Mechanism', default: 'static' },
85
+ build_schedule: { type: 'string', title: 'Build Schedule' },
86
+ build_status: { type: 'string', title: 'Build Status' },
87
+ build_status_modified_at: { type: 'modified_at', title: 'Build Status Modified At' }
88
+ }
89
+ },
90
+ uiSchema: {},
91
+ onSave: {
92
+ action: 'navigate',
93
+ url: '/segments/{{record.id}}'
94
+ }
95
+ }
96
+ },
97
+ {
98
+ component: 'RecordTable',
99
+ properties: {
100
+ table: 'person_segment',
101
+ includes: [{ alias: 'people', table: 'person' }],
102
+ conditions: [{ eql: 'segment_id={{parameters.segment_id}}' }],
103
+ columns: [
104
+ {
105
+ template: '{{person_id}}'
106
+ }
107
+ ]
108
+ }
109
+ }
110
+ ]
111
+ }
112
+ },
113
+ '/person/:id/*': {
114
+ components: {
115
+ sidebar: {
116
+ items2: [
117
+ {
118
+ component: 'Link',
119
+ properties: {
120
+ label: 'Segments',
121
+ to: 'segments'
122
+ }
123
+ }
124
+ ]
125
+ },
126
+ main: [
127
+ {
128
+ path: 'segments',
129
+ label: 'Segments',
130
+ component: 'RecordTable',
131
+ properties: {
132
+ table: 'person_segment',
133
+ includes: [{ alias: 'segments', table: 'segment' }],
134
+ conditions: [{ eql: 'person_id={{parameters.person_id}}' }],
135
+ rows: ['{{segment}}']
136
+ }
137
+ }
138
+ ]
139
+ }
140
+ }
141
+ }
142
+ }
@@ -0,0 +1,16 @@
1
+ import schema from './schema.js';
2
+
3
+ const metadata = {
4
+ name: '@engine9/schemas/segment_stats',
5
+ schemas: ['schema.js'],
6
+ dependencies: {
7
+ '@engine9/schemas/segment': '>=1.9.0'
8
+ }
9
+ };
10
+
11
+ export { metadata };
12
+ export { schema };
13
+ export default {
14
+ metadata,
15
+ schema
16
+ };
@@ -0,0 +1,30 @@
1
+ export const tables = [
2
+ {
3
+ name: 'segment_stats',
4
+ columns: {
5
+ id: 'id',
6
+ segment_id: 'foreign_id',
7
+ transactions: 'int',
8
+ revenue: 'currency',
9
+ created_at: 'created_at',
10
+ modified_at: 'modified_at'
11
+ },
12
+ indexes: [{ columns: ['segment_id'] }]
13
+ },
14
+ {
15
+ name: 'segment_stats_by_date',
16
+ columns: {
17
+ id: 'id',
18
+ segment_id: 'foreign_id',
19
+ date: 'date',
20
+ transactions: 'int',
21
+ revenue: 'currency',
22
+ created_at: 'created_at',
23
+ modified_at: 'modified_at'
24
+ },
25
+ indexes: [{ columns: ['segment_id', 'date'], unique: true }]
26
+ }
27
+ ];
28
+ export default {
29
+ tables
30
+ };
@@ -0,0 +1,16 @@
1
+ import schema from './schema.js';
2
+ import metrics from './metrics.js';
3
+ const metadata = {
4
+ name: '@engine9/schemas/source_code',
5
+ dependencies: {
6
+ '@engine9/schemas/person': '>=1.9.0'
7
+ }
8
+ };
9
+ export { metadata };
10
+ export { schema };
11
+ export { metrics };
12
+ export default {
13
+ metadata,
14
+ schema,
15
+ metrics
16
+ };
@@ -0,0 +1,28 @@
1
+ export const parsing = {
2
+ label: 'Overall Parsing',
3
+ description: '',
4
+ eql: {
5
+ table: 'source_code_summary',
6
+ columns: [
7
+ { eql: 'count(*)', name: 'records' },
8
+ { eql: 'sum(case when length(format)>0 then 1 else 0 end)', name: 'parsed' }
9
+ ],
10
+ conditions: []
11
+ }
12
+ };
13
+ export const recent_parsing = {
14
+ label: 'Parsing last 30 days',
15
+ description: '',
16
+ eql: {
17
+ table: 'source_code_summary',
18
+ columns: [
19
+ { eql: 'count(*)', name: 'records' },
20
+ { eql: 'sum(case when length(format)>0 then 1 else 0 end)', name: 'parsed' }
21
+ ],
22
+ conditions: [{ eql: 'date_sub(now(), interval 30 day)' }]
23
+ }
24
+ };
25
+ export default {
26
+ parsing,
27
+ recent_parsing
28
+ };
@@ -0,0 +1,29 @@
1
+ export const tables = [
2
+ {
3
+ name: 'source_code_dictionary',
4
+ columns: {
5
+ source_code_id: 'id',
6
+ source_code: {
7
+ type: 'string',
8
+ length: 180,
9
+ nullable: false,
10
+ default_value: ''
11
+ },
12
+ format: 'string',
13
+ format_regex: 'string',
14
+ source_code_channel: 'string',
15
+ source_code_last_used: 'created_at', //by default, when this record is created it needs a last used.
16
+ parsing: 'json',
17
+ created_at: 'created_at',
18
+ modified_at: 'modified_at'
19
+ },
20
+ indexes: [
21
+ { columns: 'source_code_id', primary: true },
22
+ { columns: 'source_code', unique: true },
23
+ { columns: 'source_code_last_used' }
24
+ ]
25
+ }
26
+ ];
27
+ export default {
28
+ tables
29
+ };