@suss/packs 0.31.2 → 0.33.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.
@@ -11,6 +11,9 @@ import '@suss/framework-aws-sns';
11
11
  import '@suss/framework-aws-sqs';
12
12
  import '@suss/framework-aws-ssm';
13
13
  import '@suss/client-axios';
14
+ import '@suss/framework-bigquery-python';
15
+ import '@suss/framework-bigquery-ruby';
16
+ import '@suss/framework-bigquery';
14
17
  import '@suss/framework-cloudflare-workers';
15
18
  import '@suss/framework-drizzle';
16
19
  import '@suss/framework-express';
@@ -31,6 +34,8 @@ import '@suss/client-net-http';
31
34
  import '@suss/framework-nextjs';
32
35
  import '@suss/runtime-node';
33
36
  import '@suss/framework-package-exports';
37
+ import '@suss/framework-pg-ruby';
38
+ import '@suss/framework-pg';
34
39
  import '@suss/framework-prisma';
35
40
  import '@suss/framework-rails';
36
41
  import '@suss/framework-react-query';
@@ -98,6 +98,58 @@ var RETURNS_A_RELATION = [
98
98
  "except"
99
99
  ];
100
100
  var READS = [...RUNS_A_QUERY, ...RETURNS_A_RELATION, "not"];
101
+ var TAKES_A_STATEMENT = {
102
+ find_by_sql: { at: 0 },
103
+ count_by_sql: { at: 0 }
104
+ };
105
+ var CONNECTION_STATEMENTS = {
106
+ execute: { at: 0 },
107
+ exec_query: { at: 0 },
108
+ exec_insert: { at: 0 },
109
+ exec_update: { at: 0 },
110
+ exec_delete: { at: 0 },
111
+ select_all: { at: 0 },
112
+ select_one: { at: 0 },
113
+ select_value: { at: 0 },
114
+ select_values: { at: 0 },
115
+ select_rows: { at: 0 }
116
+ };
117
+ var EVENT_OF = {
118
+ create: ["create"],
119
+ "create!": ["create"],
120
+ find_or_create_by: ["create"],
121
+ "find_or_create_by!": ["create"],
122
+ save: ["create", "update"],
123
+ "save!": ["create", "update"],
124
+ update: ["update"],
125
+ "update!": ["update"],
126
+ touch: ["update"],
127
+ upsert: ["create", "update"],
128
+ destroy: ["destroy"],
129
+ "destroy!": ["destroy"],
130
+ destroy_all: ["destroy"]
131
+ };
132
+ var REGISTERED_BY = {
133
+ before_validation: ["create", "update"],
134
+ after_validation: ["create", "update"],
135
+ before_save: ["create", "update"],
136
+ around_save: ["create", "update"],
137
+ after_save: ["create", "update"],
138
+ before_create: ["create"],
139
+ around_create: ["create"],
140
+ after_create: ["create"],
141
+ before_update: ["update"],
142
+ around_update: ["update"],
143
+ after_update: ["update"],
144
+ before_destroy: ["destroy"],
145
+ around_destroy: ["destroy"],
146
+ after_destroy: ["destroy"],
147
+ after_commit: ["create", "update", "destroy"],
148
+ after_rollback: ["create", "update", "destroy"],
149
+ after_create_commit: ["create"],
150
+ after_update_commit: ["update"],
151
+ after_destroy_commit: ["destroy"]
152
+ };
101
153
  function activeRecordStorage(options) {
102
154
  return [
103
155
  {
@@ -131,6 +183,13 @@ function activeRecordStorage(options) {
131
183
  methods: ["find", "exists?", "update", "destroy", "delete"],
132
184
  column: "id"
133
185
  },
186
+ statements: TAKES_A_STATEMENT,
187
+ bindPlaceholder: "?",
188
+ callbacks: {
189
+ eventOf: EVENT_OF,
190
+ registeredBy: REGISTERED_BY,
191
+ eventKeyword: "on"
192
+ },
134
193
  columnArguments: ["select", "pluck", "pick"],
135
194
  associations: {
136
195
  singular: ["has_one", "belongs_to"],
@@ -141,6 +200,18 @@ function activeRecordStorage(options) {
141
200
  }
142
201
  ];
143
202
  }
203
+ function activeRecordRawSql(options) {
204
+ return [
205
+ {
206
+ constantName: "ActiveRecord::Base",
207
+ baseClasses: ["ActiveRecord::Base"],
208
+ clientBuilders: ["connection", "lease_connection", "retrieve_connection"],
209
+ statements: CONNECTION_STATEMENTS,
210
+ storageSystem: options.storageSystem,
211
+ dialect: options.storageSystem
212
+ }
213
+ ];
214
+ }
144
215
  function activeRecordFramework(options) {
145
216
  if (typeof options?.storageSystem !== "string") {
146
217
  throw new Error(
@@ -151,7 +222,8 @@ function activeRecordFramework(options) {
151
222
  name: "activerecord",
152
223
  protocol: options.storageSystem,
153
224
  discovery: [],
154
- storage: activeRecordStorage(options)
225
+ storage: activeRecordStorage(options),
226
+ rawSql: activeRecordRawSql(options)
155
227
  };
156
228
  }
157
229
  var declares = {
@@ -161,7 +233,7 @@ var declares = {
161
233
  { ecosystem: "rubygems", name: "activerecord" },
162
234
  { ecosystem: "rubygems", name: "rails" }
163
235
  ],
164
- reads: "ActiveRecord calls (Ruby): a call matches when its method is one ActiveRecord defines as a read or a write and the class behind its receiver reaches `ActiveRecord::Base`, following what each class extends through the project.",
236
+ reads: "ActiveRecord calls (Ruby): a call matches when its method is one ActiveRecord defines as a read or a write and the class behind its receiver reaches `ActiveRecord::Base`, following what each class extends through the project. Statements the project wrote itself are read for the tables they touch, whether they went through `find_by_sql` and `count_by_sql` or through the connection. A write also runs the model's callbacks, and what they reach lands on the body that did the write.",
165
237
  configuration: {
166
238
  file: "suss.activerecord.json",
167
239
  example: { storageSystem: "postgresql" },
@@ -413,6 +413,18 @@ function awsLambdaFramework(_options = {}) {
413
413
  { position: 1, role: "context" }
414
414
  ]
415
415
  },
416
+ // A proxy integration hands the handler API Gateway's event. The
417
+ // body arrives on it as a string the handler parses, so a read of
418
+ // it says the body was taken whole and never which field.
419
+ requestSpelling: {
420
+ headers: { path: ["event", "headers"], saysWhichField: true },
421
+ query: {
422
+ path: ["event", "queryStringParameters"],
423
+ saysWhichField: true
424
+ },
425
+ params: { path: ["event", "pathParameters"], saysWhichField: true },
426
+ body: { path: ["event", "body"], saysWhichField: false }
427
+ },
416
428
  // The powertools read their configuration from inside node_modules,
417
429
  // so a template that declares these has a reader no walk ever sees.
418
430
  libraryEnvVars: [
package/dist/axios.js CHANGED
@@ -40,7 +40,8 @@ function discoveryForVerb(verb, factories) {
40
40
  importModule: "axios",
41
41
  importName: "axios",
42
42
  methodFilter: [verb],
43
- factoryMethods: ["create"]
43
+ factoryMethods: ["create"],
44
+ basePathOption: "baseURL"
44
45
  },
45
46
  bindingExtraction: {
46
47
  method: { type: "literal", value: verb.toUpperCase() },
@@ -56,7 +57,8 @@ function discoveryForVerb(verb, factories) {
56
57
  type: "clientCall",
57
58
  importModule: factory.module,
58
59
  importName: factory.export,
59
- methodFilter: [verb]
60
+ methodFilter: [verb],
61
+ basePathOption: "baseURL"
60
62
  },
61
63
  bindingExtraction: {
62
64
  method: { type: "literal", value: verb.toUpperCase() },
@@ -101,7 +103,8 @@ function configCallDiscovery(factories) {
101
103
  importName: "axios",
102
104
  methodFilter: ["request"],
103
105
  factoryMethods: ["create"],
104
- callable: true
106
+ callable: true,
107
+ basePathOption: "baseURL"
105
108
  },
106
109
  bindingExtraction,
107
110
  requiresImport: ["axios"]
@@ -114,7 +117,8 @@ function configCallDiscovery(factories) {
114
117
  type: "clientCall",
115
118
  importModule: factory.module,
116
119
  importName: factory.export,
117
- methodFilter: ["request"]
120
+ methodFilter: ["request"],
121
+ basePathOption: "baseURL"
118
122
  },
119
123
  bindingExtraction,
120
124
  requiresImport: isPathShapedSpecifier(factory.module) ? [] : [factory.module]
@@ -0,0 +1 @@
1
+ export { declares, default } from '@suss/framework-bigquery-python';
@@ -0,0 +1,122 @@
1
+ // ../framework/bigquery-python/dist/index.js
2
+ var STORAGE_SYSTEM = "gcp.bigquery";
3
+ var DIALECT = "bigquery";
4
+ var CLIENT_MODULE = "google.cloud.bigquery";
5
+ var HOOK_MODULE = "airflow.providers.google.cloud.hooks.bigquery";
6
+ var CLIENT_STATEMENTS = [
7
+ { method: "query", argument: 0, keyword: "query" },
8
+ { method: "query_and_wait", argument: 0, keyword: "query" }
9
+ ];
10
+ var CLIENT_TABLES = [
11
+ { method: "get_table", argument: 0, keyword: "table", kind: "read" },
12
+ { method: "list_rows", argument: 0, keyword: "table", kind: "read" },
13
+ {
14
+ method: "insert_rows",
15
+ argument: 0,
16
+ keyword: "table",
17
+ kind: "write"
18
+ },
19
+ {
20
+ method: "insert_rows_json",
21
+ argument: 0,
22
+ keyword: "table",
23
+ kind: "write"
24
+ },
25
+ {
26
+ method: "delete_table",
27
+ argument: 0,
28
+ keyword: "table",
29
+ kind: "write"
30
+ },
31
+ {
32
+ method: "load_table_from_dataframe",
33
+ argument: 1,
34
+ keyword: "destination",
35
+ kind: "write"
36
+ },
37
+ {
38
+ method: "load_table_from_json",
39
+ argument: 1,
40
+ keyword: "destination",
41
+ kind: "write"
42
+ },
43
+ {
44
+ method: "load_table_from_uri",
45
+ argument: 1,
46
+ keyword: "destination",
47
+ kind: "write"
48
+ },
49
+ {
50
+ method: "load_table_from_file",
51
+ argument: 1,
52
+ keyword: "destination",
53
+ kind: "write"
54
+ }
55
+ ];
56
+ var HOOK_STATEMENTS = [
57
+ { method: "get_records", argument: 0, keyword: "sql" },
58
+ { method: "get_first", argument: 0, keyword: "sql" },
59
+ { method: "get_pandas_df", argument: 0, keyword: "sql" },
60
+ { method: "run_query", argument: 0, keyword: "sql" },
61
+ {
62
+ method: "insert_job",
63
+ argument: 0,
64
+ keyword: "configuration",
65
+ path: ["query", "query"]
66
+ }
67
+ ];
68
+ var HOOK_TABLES = [
69
+ {
70
+ method: "delete_table",
71
+ argument: 0,
72
+ keyword: "table_id",
73
+ kind: "write"
74
+ }
75
+ ];
76
+ function bigqueryClients() {
77
+ return [
78
+ {
79
+ module: CLIENT_MODULE,
80
+ clientTypes: ["Client"],
81
+ statements: CLIENT_STATEMENTS,
82
+ tables: CLIENT_TABLES,
83
+ storageSystem: STORAGE_SYSTEM,
84
+ dialect: DIALECT
85
+ },
86
+ {
87
+ module: HOOK_MODULE,
88
+ clientTypes: ["BigQueryHook"],
89
+ statements: HOOK_STATEMENTS,
90
+ tables: HOOK_TABLES,
91
+ // The hook documents `get_client` as handing back the client
92
+ // library's own `Client`, so a chain off it reads as one.
93
+ handsBack: [
94
+ { method: "get_client", module: CLIENT_MODULE, name: "Client" }
95
+ ],
96
+ storageSystem: STORAGE_SYSTEM,
97
+ dialect: DIALECT
98
+ }
99
+ ];
100
+ }
101
+ function bigqueryFramework() {
102
+ return {
103
+ name: "bigquery-python",
104
+ protocol: STORAGE_SYSTEM,
105
+ discovery: [],
106
+ sqlClients: bigqueryClients()
107
+ };
108
+ }
109
+ var declares = {
110
+ kind: "effects",
111
+ package: "@suss/framework-bigquery-python",
112
+ dependencies: [
113
+ { ecosystem: "pypi", name: "google-cloud-bigquery" },
114
+ { ecosystem: "pypi", name: "apache-airflow-providers-google" }
115
+ ],
116
+ reads: "BigQuery calls (Python): the statement a client or an Airflow hook is handed, read for the tables it touches, and the calls that say which table without writing SQL."
117
+ };
118
+ var index_default = bigqueryFramework;
119
+ export {
120
+ declares,
121
+ index_default as default
122
+ };
@@ -0,0 +1 @@
1
+ export { declares, default } from '@suss/framework-bigquery-ruby';
@@ -0,0 +1,56 @@
1
+ // ../framework/bigquery-ruby/dist/index.js
2
+ var STORAGE_SYSTEM = "gcp.bigquery";
3
+ var DIALECT = "bigquery";
4
+ var ADDRESSING = {
5
+ dataset: { says: "scope", at: 0 },
6
+ table: { says: "container", at: 0 }
7
+ };
8
+ var STATEMENTS = {
9
+ query: { at: 0 },
10
+ query_job: { at: 0 }
11
+ };
12
+ var ROW_CALLS = {
13
+ insert: { kind: "write", container: { at: 0 } },
14
+ insert_async: { kind: "write", container: { at: 0 } },
15
+ load: { kind: "write", container: { at: 0 } },
16
+ load_job: { kind: "write", container: { at: 0 } },
17
+ data: { kind: "read" },
18
+ "exists?": { kind: "read" },
19
+ delete: { kind: "write" }
20
+ };
21
+ function bigqueryRawSql() {
22
+ const calls = {
23
+ addressing: ADDRESSING,
24
+ statements: STATEMENTS,
25
+ rowCalls: ROW_CALLS,
26
+ storageSystem: STORAGE_SYSTEM,
27
+ dialect: DIALECT
28
+ };
29
+ return [
30
+ {
31
+ constantName: "Google::Cloud::Bigquery",
32
+ clientBuilders: ["new"],
33
+ ...calls
34
+ },
35
+ { constantName: "Google::Cloud", clientBuilders: ["bigquery"], ...calls }
36
+ ];
37
+ }
38
+ function bigqueryRubyFramework() {
39
+ return {
40
+ name: "bigquery-ruby",
41
+ protocol: STORAGE_SYSTEM,
42
+ discovery: [],
43
+ rawSql: bigqueryRawSql()
44
+ };
45
+ }
46
+ var declares = {
47
+ kind: "effects",
48
+ package: "@suss/framework-bigquery-ruby",
49
+ dependencies: [{ ecosystem: "rubygems", name: "google-cloud-bigquery" }],
50
+ reads: "google-cloud-bigquery calls (Ruby): a call matches when its receiver follows back to a client the gem handed out, and the statement it was given is parsed for the tables it touches."
51
+ };
52
+ var index_default = bigqueryRubyFramework;
53
+ export {
54
+ declares,
55
+ index_default as default
56
+ };
@@ -0,0 +1 @@
1
+ export { declares, default } from '@suss/framework-bigquery';
@@ -0,0 +1,54 @@
1
+ // ../framework/bigquery/dist/index.js
2
+ import { declaredBy, pack, sqlStatements, storageCalls } from "@suss/recognize";
3
+ var CLIENT_MODULE = "@google-cloud/bigquery";
4
+ var STORAGE_SYSTEM = "gcp.bigquery";
5
+ var STATEMENT = {
6
+ statement: [{ at: 0 }, { at: 0, property: ["query"] }]
7
+ };
8
+ var QUERIES = sqlStatements({
9
+ system: STORAGE_SYSTEM,
10
+ dialect: "bigquery",
11
+ client: declaredBy(CLIENT_MODULE)
12
+ }).methods({
13
+ query: STATEMENT,
14
+ createQueryJob: STATEMENT,
15
+ createQueryStream: STATEMENT
16
+ }).example(
17
+ 'bigquery.query("SELECT id, name FROM `analytics.core.dim_account`")'
18
+ );
19
+ var DATASET_STEP = { to: "receiver", method: "dataset" };
20
+ var TABLE_STEP = { to: "receiver", method: "table" };
21
+ var TABLE = { of: [TABLE_STEP], at: 0 };
22
+ var DATASET = { of: [DATASET_STEP], at: 0 };
23
+ var READ_ROWS = { kind: "read", fields: ["*"] };
24
+ var WRITE_ROWS = { kind: "write", fields: ["*"] };
25
+ var READ_TABLE = { kind: "read" };
26
+ var DROP_TABLE = { kind: "write" };
27
+ var OPERATIONS = {
28
+ insert: WRITE_ROWS,
29
+ load: WRITE_ROWS,
30
+ getRows: READ_ROWS,
31
+ exists: READ_TABLE,
32
+ delete: DROP_TABLE
33
+ };
34
+ var TABLE_CALLS = storageCalls({
35
+ system: STORAGE_SYSTEM,
36
+ client: declaredBy(CLIENT_MODULE)
37
+ }).methods(OPERATIONS).container(TABLE).scope(DATASET).example('bigquery.dataset("core").table("dim_account").insert(rows)');
38
+ function bigqueryFramework() {
39
+ return pack("bigquery", [QUERIES, TABLE_CALLS], {
40
+ languages: ["typescript", "javascript"],
41
+ recognizedAs: "@suss/framework-bigquery"
42
+ });
43
+ }
44
+ var declares = {
45
+ kind: "effects",
46
+ package: "@suss/framework-bigquery",
47
+ dependencies: [{ ecosystem: "npm", name: "@google-cloud/bigquery" }],
48
+ reads: "BigQuery queries and table calls, emits storage-access interactions with the dataset as the scope."
49
+ };
50
+ var index_default = bigqueryFramework;
51
+ export {
52
+ declares,
53
+ index_default as default
54
+ };
package/dist/express.js CHANGED
@@ -173,6 +173,14 @@ function expressFramework(_options = {}) {
173
173
  { position: 1, role: "response" },
174
174
  { position: 2, role: "next" }
175
175
  ]
176
+ },
177
+ // Express puts all four parts on the request object, and a handler
178
+ // reads a field of each by name.
179
+ requestSpelling: {
180
+ headers: { path: ["request", "headers"], saysWhichField: true },
181
+ query: { path: ["request", "query"], saysWhichField: true },
182
+ params: { path: ["request", "params"], saysWhichField: true },
183
+ body: { path: ["request", "body"], saysWhichField: true }
176
184
  }
177
185
  };
178
186
  }
package/dist/fastify.js CHANGED
@@ -118,6 +118,14 @@ function fastifyFramework(_options = {}) {
118
118
  { position: 0, role: "request" },
119
119
  { position: 1, role: "reply" }
120
120
  ]
121
+ },
122
+ // Fastify puts all four parts on the request object, and a handler
123
+ // reads a field of each by name.
124
+ requestSpelling: {
125
+ headers: { path: ["request", "headers"], saysWhichField: true },
126
+ query: { path: ["request", "query"], saysWhichField: true },
127
+ params: { path: ["request", "params"], saysWhichField: true },
128
+ body: { path: ["request", "body"], saysWhichField: true }
121
129
  }
122
130
  };
123
131
  }
@@ -109,7 +109,10 @@ function graphqlRubyFramework(options) {
109
109
  "dataload_all",
110
110
  "dataload_record",
111
111
  "dataload_all_records"
112
- ]
112
+ ],
113
+ // The library runs `fetch` on the source class `with` was given,
114
+ // so whatever that method reaches belongs to the field.
115
+ source: { at: 0, method: "fetch" }
113
116
  }
114
117
  ]
115
118
  };
package/dist/hono.js CHANGED
@@ -208,6 +208,14 @@ function honoFramework(_options = {}) {
208
208
  inputMapping: {
209
209
  type: "positionalParams",
210
210
  params: [{ position: 0, role: "context" }]
211
+ },
212
+ // `c.req.header("x-tenant-id")` puts the field in the argument, and
213
+ // a read records the method without it, so no read says which field.
214
+ requestSpelling: {
215
+ headers: { path: ["context", "req", "header"], saysWhichField: false },
216
+ query: { path: ["context", "req", "query"], saysWhichField: false },
217
+ params: { path: ["context", "req", "param"], saysWhichField: false },
218
+ body: { path: ["context", "req", "json"], saysWhichField: false }
211
219
  }
212
220
  };
213
221
  }