weaverstack 0.1.1__py3-none-any.whl

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 (127) hide show
  1. weaver/__init__.py +59 -0
  2. weaver/build_bundle/__init__.py +109 -0
  3. weaver/build_bundle/aliases.py +325 -0
  4. weaver/build_bundle/bundle.py +359 -0
  5. weaver/build_bundle/catalogue_actions.py +275 -0
  6. weaver/build_bundle/changes.py +186 -0
  7. weaver/build_bundle/endpoints.py +83 -0
  8. weaver/build_bundle/executors/__init__.py +69 -0
  9. weaver/build_bundle/executors/alias.py +202 -0
  10. weaver/build_bundle/executors/base.py +132 -0
  11. weaver/build_bundle/executors/folder.py +71 -0
  12. weaver/build_bundle/executors/load_file.py +205 -0
  13. weaver/build_bundle/executors/spark_case.py +26 -0
  14. weaver/build_bundle/executors/spark_schema.py +60 -0
  15. weaver/build_bundle/executors/spark_sql.py +59 -0
  16. weaver/build_bundle/executors/spark_sql_batch.py +57 -0
  17. weaver/build_bundle/executors/spark_table.py +213 -0
  18. weaver/build_bundle/executors/sql_endpoint_refresh.py +34 -0
  19. weaver/build_bundle/executors/tsql.py +81 -0
  20. weaver/build_bundle/incremental.py +288 -0
  21. weaver/build_bundle/installer.py +384 -0
  22. weaver/build_bundle/models.py +288 -0
  23. weaver/build_bundle/payloads.py +34 -0
  24. weaver/build_bundle/physical.py +625 -0
  25. weaver/build_bundle/planner.py +389 -0
  26. weaver/build_bundle/prune.py +620 -0
  27. weaver/build_bundle/report.py +108 -0
  28. weaver/build_bundle/stages.py +196 -0
  29. weaver/build_bundle/targets.py +272 -0
  30. weaver/build_bundle/workflow.py +585 -0
  31. weaver/catalogue/__init__.py +73 -0
  32. weaver/catalogue/builtin.py +238 -0
  33. weaver/catalogue/claims.py +121 -0
  34. weaver/catalogue/projection.py +437 -0
  35. weaver/catalogue/reader.py +152 -0
  36. weaver/catalogue/reconcile.py +231 -0
  37. weaver/catalogue/render.py +410 -0
  38. weaver/catalogue/state.py +660 -0
  39. weaver/catalogue/tables.py +648 -0
  40. weaver/config.py +178 -0
  41. weaver/declaration/__init__.py +171 -0
  42. weaver/declaration/columns.py +223 -0
  43. weaver/declaration/ddl.py +266 -0
  44. weaver/declaration/dependencies.py +544 -0
  45. weaver/declaration/graph.py +240 -0
  46. weaver/declaration/item_dependencies.py +292 -0
  47. weaver/declaration/load.py +191 -0
  48. weaver/declaration/metadata.py +1405 -0
  49. weaver/declaration/model.py +448 -0
  50. weaver/declaration/references.py +294 -0
  51. weaver/declaration/repository.py +959 -0
  52. weaver/declaration/schemas.py +135 -0
  53. weaver/declaration/source.py +674 -0
  54. weaver/declaration/spark_load.py +759 -0
  55. weaver/declaration/sql_shaping.py +591 -0
  56. weaver/declaration/templates/ddl/declared_create_table.sql +64 -0
  57. weaver/declaration/templates/ddl/infer_create_table.sql +97 -0
  58. weaver/declaration/templates/ddl/metadata_column_validation.sql +30 -0
  59. weaver/declaration/templates/load/column_metadata.sql +40 -0
  60. weaver/declaration/templates/load/full_replace_body.sql +21 -0
  61. weaver/declaration/templates/load/install_load_procedure.sql +27 -0
  62. weaver/declaration/templates/load/load_procedure.sql +48 -0
  63. weaver/declaration/templates/load/primary_key_body.sql +113 -0
  64. weaver/declaration/tsql_ddl.py +468 -0
  65. weaver/declaration/tsql_load.py +417 -0
  66. weaver/declaration/warehouse_type_mapping.yml +93 -0
  67. weaver/diagnostics.py +247 -0
  68. weaver/errors.py +61 -0
  69. weaver/etl.py +469 -0
  70. weaver/fabric/__init__.py +107 -0
  71. weaver/fabric/auth.py +137 -0
  72. weaver/fabric/capacity.py +143 -0
  73. weaver/fabric/client.py +147 -0
  74. weaver/fabric/environment.py +460 -0
  75. weaver/fabric/livy.py +478 -0
  76. weaver/fabric/notebooks.py +201 -0
  77. weaver/fabric/onelake.py +263 -0
  78. weaver/fabric/resolution.py +344 -0
  79. weaver/fabric/resources.py +245 -0
  80. weaver/fabric/session.py +148 -0
  81. weaver/fabric/shortcuts.py +120 -0
  82. weaver/fabric/sql.py +118 -0
  83. weaver/fabric/store.py +198 -0
  84. weaver/initialise.py +209 -0
  85. weaver/lakehouse.py +386 -0
  86. weaver/load.py +474 -0
  87. weaver/load_execution.py +483 -0
  88. weaver/load_plan.py +912 -0
  89. weaver/load_report.py +330 -0
  90. weaver/load_resolution.py +386 -0
  91. weaver/locations.py +164 -0
  92. weaver/objects.py +392 -0
  93. weaver/operations.py +757 -0
  94. weaver/physical_wipe.py +369 -0
  95. weaver/push.py +76 -0
  96. weaver/resolution.py +292 -0
  97. weaver/runtime/__init__.py +30 -0
  98. weaver/runtime/folder_load.py +402 -0
  99. weaver/runtime/load_contract.py +245 -0
  100. weaver/runtime/load_result.py +104 -0
  101. weaver/runtime/spark_load.py +152 -0
  102. weaver/runtime/table_load.py +497 -0
  103. weaver/spark/__init__.py +49 -0
  104. weaver/spark/catalogue.py +245 -0
  105. weaver/spark/destination.py +195 -0
  106. weaver/spark/session.py +84 -0
  107. weaver/spark/tokens.py +138 -0
  108. weaver/sql/__init__.py +40 -0
  109. weaver/sql/authentication.py +38 -0
  110. weaver/sql/connection.py +90 -0
  111. weaver/sql/errors.py +25 -0
  112. weaver/sql/execution.py +123 -0
  113. weaver/sql/pool.py +174 -0
  114. weaver/sql/wipe.py +156 -0
  115. weaver/store.py +209 -0
  116. weaver/targets.py +257 -0
  117. weaver/task_logging.py +215 -0
  118. weaver/unbind.py +74 -0
  119. weaver/workspaces.py +175 -0
  120. weaver_cli/__init__.py +12 -0
  121. weaver_cli/__main__.py +7 -0
  122. weaver_cli/main.py +626 -0
  123. weaverstack-0.1.1.dist-info/METADATA +113 -0
  124. weaverstack-0.1.1.dist-info/RECORD +127 -0
  125. weaverstack-0.1.1.dist-info/WHEEL +4 -0
  126. weaverstack-0.1.1.dist-info/entry_points.txt +2 -0
  127. weaverstack-0.1.1.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,97 @@
1
+ declare @weaver_create_sql nvarchar(max);
2
+ declare @weaver_pk_sql nvarchar(max);
3
+
4
+ if not exists (
5
+ select 1
6
+ from tempdb.sys.columns as c
7
+ where c.[object_id] = object_id($temp_object_literal)
8
+ )
9
+ begin
10
+ throw 51001, 'weaver found no temp table columns to create.', 1;
11
+ end;
12
+
13
+ $metadata_validation_sql
14
+
15
+ $identity_guard_sql
16
+
17
+ ;with primary_key_columns as (
18
+ $primary_key_columns_cte
19
+ ),
20
+ not_null_columns as (
21
+ $not_null_columns_cte
22
+ ),
23
+ described as (
24
+ select
25
+ c.column_id as column_ordinal,
26
+ coalesce(nullif(c.name, ''), concat('Column', c.column_id)) as column_name,
27
+ t.name as system_type_name,
28
+ c.max_length,
29
+ c.precision,
30
+ c.scale
31
+ from tempdb.sys.columns as c
32
+ inner join tempdb.sys.types as t on t.user_type_id = c.user_type_id
33
+ where c.[object_id] = object_id($temp_object_literal)
34
+ ),
35
+ mapped as (
36
+ select
37
+ d.column_ordinal,
38
+ quotename(d.column_name) as quoted_column_name,
39
+ $type_case as warehouse_type,
40
+ -- Nullability is a Weaver contract from the Weaver document header (primary key or
41
+ -- Not null), not the query's own nullability, so both engines agree.
42
+ case
43
+ when nn.column_name is not null then N' not null'
44
+ else N' null'
45
+ end as nullability
46
+ from described as d
47
+ left join not_null_columns as nn
48
+ on nn.column_name = d.column_name collate Latin1_General_BIN2
49
+ cross apply (
50
+ select lower(d.system_type_name) as base_type
51
+ ) as bt
52
+ ),
53
+ all_columns as (
54
+ $identity_column_sql select
55
+ column_ordinal,
56
+ quoted_column_name + N' ' + warehouse_type + nullability as column_definition
57
+ from mapped
58
+
59
+ union all
60
+
61
+ select 1000001, N'[Row insert datetime] datetime2(6) not null'
62
+ union all
63
+ select 1000002, N'[Row update datetime] datetime2(6) not null'
64
+ union all
65
+ select 1000003, N'[Row delete datetime] datetime2(6) not null'
66
+ )
67
+ select
68
+ @weaver_create_sql = (
69
+ select
70
+ N'create table $target_table (' + char(10)
71
+ + string_agg(
72
+ case
73
+ when column_ordinal = $first_ordinal then N' ' + column_definition
74
+ else N' , ' + column_definition
75
+ end,
76
+ char(10)
77
+ ) within group (order by column_ordinal)
78
+ + char(10) + N');'
79
+ from all_columns
80
+ ),
81
+ @weaver_pk_sql = (
82
+ select
83
+ N'alter table $target_table add constraint $pk_constraint '
84
+ + N'primary key nonclustered ('
85
+ + string_agg(quotename(column_name), N', ') within group (order by column_ordinal)
86
+ + N') not enforced;'
87
+ from primary_key_columns
88
+ );
89
+
90
+ print @weaver_create_sql;
91
+ exec sys.sp_executesql @weaver_create_sql;
92
+
93
+ if @weaver_pk_sql is not null
94
+ begin
95
+ print @weaver_pk_sql;
96
+ exec sys.sp_executesql @weaver_pk_sql;
97
+ end;
@@ -0,0 +1,30 @@
1
+ declare @weaver_missing_metadata_column nvarchar(2048);
2
+
3
+ ;with described as (
4
+ select
5
+ coalesce(nullif(c.name, ''), concat('Column', c.column_id)) as column_name
6
+ from tempdb.sys.columns as c
7
+ where c.[object_id] = object_id($temp_object_literal)$identity_available_sql
8
+ ),
9
+ metadata_columns as (
10
+ $metadata_columns_cte
11
+ )
12
+ select top (1)
13
+ @weaver_missing_metadata_column =
14
+ concat(m.metadata_kind, N' ', m.column_name, N' does not exist')
15
+ from metadata_columns as m
16
+ where not exists (
17
+ select 1
18
+ from described as d
19
+ -- Column names are exact, case-sensitive Weaver contracts, so compare under
20
+ -- a binary collation rather than the database's (often case-insensitive) one.
21
+ where d.column_name = m.column_name collate Latin1_General_BIN2
22
+ )
23
+ order by
24
+ m.metadata_kind
25
+ , m.column_name;
26
+
27
+ if @weaver_missing_metadata_column is not null
28
+ begin
29
+ throw 51004, @weaver_missing_metadata_column, 1;
30
+ end;
@@ -0,0 +1,40 @@
1
+ -- The loadable columns, read from the table the load will write to.
2
+ --
3
+ -- Read from sys.columns rather than from the declaration, because the physical
4
+ -- table is what the procedure has to name. That is also what excludes the
5
+ -- identity column for free: the Warehouse generates it, so `is_identity = 0`
6
+ -- keeps it out of every insert list without the generator having to know which
7
+ -- column it was.
8
+ ;with source_columns as (
9
+ select
10
+ c.name
11
+ , c.column_id
12
+ , row_number() over (order by c.column_id) as row_ordinal
13
+ from sys.columns as c
14
+ where c.[object_id] = object_id($target_table_literal)
15
+ and $source_column_filter
16
+ )
17
+ select
18
+ @weaver_source_columns = string_agg(
19
+ case when row_ordinal = 1 then quotename(name) else char(10) + N' , ' + quotename(name) end,
20
+ N''
21
+ ) within group (order by column_id)
22
+ , @weaver_staging_select_columns = string_agg(
23
+ case when row_ordinal = 1 then N's.' + quotename(name) else char(10) + N' , s.' + quotename(name) end,
24
+ N''
25
+ ) within group (order by column_id)
26
+ , @weaver_staging_except_columns = string_agg(
27
+ case when row_ordinal = 1 then N's.' + quotename(name) else char(10) + N' , s.' + quotename(name) end,
28
+ N''
29
+ ) within group (order by column_id)
30
+ , @weaver_target_except_columns = string_agg(
31
+ case when row_ordinal = 1 then N't.' + quotename(name) else char(10) + N' , t.' + quotename(name) end,
32
+ N''
33
+ ) within group (order by column_id)
34
+ , @weaver_upsert_select_columns = string_agg(
35
+ case when row_ordinal = 1 then N'u.' + quotename(name) else char(10) + N' , u.' + quotename(name) end,
36
+ N''
37
+ ) within group (order by column_id)
38
+ from source_columns;
39
+
40
+ $update_select
@@ -0,0 +1,21 @@
1
+ -- No primary key, so no row can be matched to a target row: there is no such
2
+ -- thing as an update here, and nothing to reject. The target's contents become
3
+ -- the source's.
4
+ select @weaver_target_before = count(*) from $target_table;
5
+
6
+ delete from $target_table;
7
+
8
+ insert into $target_table (
9
+ __SOURCE_COLUMNS__
10
+ , [Row insert datetime]
11
+ , [Row update datetime]
12
+ , [Row delete datetime]
13
+ )
14
+ select
15
+ __STAGING_SELECT_COLUMNS__
16
+ , @weaver_load_datetime
17
+ , @weaver_load_datetime
18
+ , @weaver_live_datetime
19
+ from $staging_table as s;
20
+
21
+ set @weaver_rows_inserted = @@rowcount;
@@ -0,0 +1,27 @@
1
+ /* weaver generated load procedure installer. */
2
+ set nocount on;
3
+
4
+ declare @weaver_proc_sql nvarchar(max);
5
+ declare @weaver_source_columns nvarchar(max);
6
+ declare @weaver_staging_select_columns nvarchar(max);
7
+ declare @weaver_staging_except_columns nvarchar(max);
8
+ declare @weaver_target_except_columns nvarchar(max);
9
+ declare @weaver_upsert_select_columns nvarchar(max);
10
+ declare @weaver_update_set_columns nvarchar(max);
11
+
12
+ $column_metadata_sql
13
+
14
+ if @weaver_source_columns is null
15
+ begin
16
+ throw 51010, 'weaver: the load target has no loadable columns. Build the table before installing its load.', 1;
17
+ end;
18
+
19
+ set @weaver_proc_sql = $procedure_template_sql_literal;
20
+ set @weaver_proc_sql = replace(@weaver_proc_sql, N'__SOURCE_COLUMNS__', @weaver_source_columns);
21
+ set @weaver_proc_sql = replace(@weaver_proc_sql, N'__STAGING_SELECT_COLUMNS__', @weaver_staging_select_columns);
22
+ set @weaver_proc_sql = replace(@weaver_proc_sql, N'__STAGING_EXCEPT_COLUMNS__', @weaver_staging_except_columns);
23
+ set @weaver_proc_sql = replace(@weaver_proc_sql, N'__TARGET_EXCEPT_COLUMNS__', @weaver_target_except_columns);
24
+ set @weaver_proc_sql = replace(@weaver_proc_sql, N'__UPSERT_SELECT_COLUMNS__', @weaver_upsert_select_columns);
25
+ set @weaver_proc_sql = replace(@weaver_proc_sql, N'__UPDATE_SET_COLUMNS__', @weaver_update_set_columns);
26
+
27
+ exec sys.sp_executesql @weaver_proc_sql;
@@ -0,0 +1,48 @@
1
+ create or alter procedure $load_procedure
2
+ @fault_tolerant bit = 0
3
+ , @ignore_stability_threshold bit = 0
4
+ as
5
+ begin
6
+ set nocount on;
7
+
8
+ declare @weaver_load_datetime datetime2(6) = sysutcdatetime();
9
+ declare @weaver_live_datetime datetime2(6) = convert(datetime2(6), '$live_delete_datetime');
10
+ declare @weaver_rows_read bigint = 0;
11
+ declare @weaver_rows_inserted bigint = 0;
12
+ declare @weaver_rows_updated bigint = 0;
13
+ declare @weaver_rows_deleted bigint = 0;
14
+ declare @weaver_rows_rejected bigint = 0;
15
+ declare @weaver_error varchar(4000) = null;
16
+ declare @weaver_target_rows bigint = 0;
17
+ declare @weaver_prospective_deletes bigint = 0;
18
+ declare @weaver_prospective_updates bigint = 0;
19
+ declare @weaver_target_before bigint = 0;
20
+
21
+ $preprocessing_banner
22
+ $start_artifact_cleanup
23
+
24
+ $staging_sql
25
+
26
+ select @weaver_rows_read = count(*) from $staging_table;
27
+
28
+ $postprocessing_banner
29
+ $load_body
30
+
31
+ $end_artifact_cleanup
32
+
33
+ -- What the target actually lost, from its own cardinality. The delete
34
+ -- driver says what the load intended; this says what happened, and the two
35
+ -- differ whenever a key named for deletion was not there to begin with.
36
+ select @weaver_rows_deleted =
37
+ @weaver_target_before + @weaver_rows_inserted - count(*)
38
+ from $target_table;
39
+
40
+ select
41
+ cast(case when @weaver_error is null then 1 else 0 end as bit) as succeeded
42
+ , @weaver_rows_read as rows_read
43
+ , @weaver_rows_inserted as rows_inserted
44
+ , @weaver_rows_updated as rows_updated
45
+ , @weaver_rows_deleted as rows_deleted
46
+ , @weaver_rows_rejected as rows_rejected
47
+ , @weaver_error as error_message;
48
+ end;
@@ -0,0 +1,113 @@
1
+ create table $reject_table as
2
+ select
3
+ __STAGING_SELECT_COLUMNS__
4
+ , case
5
+ when $staging_blank_predicate then cast('$blank_reason' as varchar(100))
6
+ else cast('$duplicate_reason' as varchar(100))
7
+ end as [$rejection_reason]
8
+ from $staging_table as s
9
+ where $staging_blank_predicate
10
+ or s.[$rank_column] > 1;
11
+
12
+ select @weaver_rows_rejected = count(*) from $reject_table;
13
+
14
+ delete s
15
+ from $staging_table as s
16
+ where $staging_blank_predicate
17
+ or s.[$rank_column] > 1;
18
+
19
+ -- Intolerant of rejects: the target is left exactly as it was. Nothing has been
20
+ -- written yet, so refusing here is a decision not to start rather than an
21
+ -- unwind — and the reject table survives as the evidence.
22
+ --
23
+ -- Raised rather than returned, so `exec [_].[Load S.N]` fails the same way
24
+ -- `.load()` does. A primitive that returned a quiet row where its sibling
25
+ -- raised would make every caller special-case which one it was talking to.
26
+ if @weaver_rows_rejected > 0 and @fault_tolerant = 0
27
+ throw 51020, '$intolerant_message', 1;
28
+
29
+ create table $upsert_table as
30
+ select
31
+ __STAGING_SELECT_COLUMNS__
32
+ , case when $target_missing_predicate then cast(1 as int) else cast(0 as int) end as [_Is new row]
33
+ from $staging_table as s
34
+ left join $target_table as t on $staging_target_join
35
+ where
36
+ $target_missing_predicate
37
+ or exists (
38
+ select __STAGING_EXCEPT_COLUMNS__
39
+ except
40
+ select __TARGET_EXCEPT_COLUMNS__
41
+ );
42
+
43
+ -- Everything this load is about to do, counted before it does any of it. A
44
+ -- breach with @fault_tolerant = 0 leaves the target exactly as it was, so
45
+ -- refusing is a decision not to start rather than an unwind.
46
+ select @weaver_target_rows = count(*) from $target_table;
47
+ set @weaver_target_before = @weaver_target_rows;
48
+ select @weaver_prospective_updates = count(*) from $upsert_table where [_Is new row] = 0;
49
+ $prospective_deletes
50
+
51
+ if @ignore_stability_threshold = 0 and @weaver_target_rows > 0
52
+ and @weaver_target_rows >= $stability_rows
53
+ begin
54
+ if @weaver_prospective_deletes * 100.0 / @weaver_target_rows > $delete_threshold
55
+ set @weaver_error = 'delete of ' + cast(@weaver_prospective_deletes as varchar(20))
56
+ + ' rows is over the $delete_threshold% threshold of '
57
+ + cast(@weaver_target_rows as varchar(20));
58
+ else if @weaver_prospective_updates * 100.0 / @weaver_target_rows > $update_threshold
59
+ set @weaver_error = 'update of ' + cast(@weaver_prospective_updates as varchar(20))
60
+ + ' rows is over the $update_threshold% threshold of '
61
+ + cast(@weaver_target_rows as varchar(20));
62
+
63
+ -- A breach never writes. Tolerating exactly the change the threshold was
64
+ -- declared to prevent would defeat the guard, so @fault_tolerant decides
65
+ -- only whether the refusal is raised or returned. Permitting it is what
66
+ -- @ignore_stability_threshold is for.
67
+ if @weaver_error is not null
68
+ begin
69
+ set @weaver_error = @weaver_error + '; the target was not modified';
70
+ if @fault_tolerant = 0
71
+ throw 51021, @weaver_error, 1;
72
+ select
73
+ cast(0 as bit) as succeeded
74
+ , @weaver_rows_read as rows_read
75
+ , cast(0 as bigint) as rows_inserted
76
+ , cast(0 as bigint) as rows_updated
77
+ , cast(0 as bigint) as rows_deleted
78
+ , @weaver_rows_rejected as rows_rejected
79
+ , @weaver_error as error_message;
80
+ return;
81
+ end;
82
+ end;
83
+
84
+ insert into $target_table (
85
+ __SOURCE_COLUMNS__
86
+ , [Row insert datetime]
87
+ , [Row update datetime]
88
+ , [Row delete datetime]
89
+ )
90
+ select
91
+ __UPSERT_SELECT_COLUMNS__
92
+ , @weaver_load_datetime
93
+ , @weaver_load_datetime
94
+ , @weaver_live_datetime
95
+ from $upsert_table as u
96
+ where u.[_Is new row] = 1;
97
+
98
+ set @weaver_rows_inserted = @@rowcount;
99
+
100
+ update c
101
+ set
102
+ __UPDATE_SET_COLUMNS__
103
+ from $target_table as c
104
+ inner join $upsert_table as u on $target_upsert_join
105
+ where u.[_Is new row] = 0;
106
+
107
+ set @weaver_rows_updated = @@rowcount;
108
+
109
+ $missing_reconciliation
110
+
111
+ if @weaver_rows_rejected > 0 and @weaver_error is null
112
+ set @weaver_error = cast(@weaver_rows_rejected as varchar(20))
113
+ + ' $tolerated_message';